diff --git a/readme.md b/readme.md index 1e4782a..87f4887 100644 --- a/readme.md +++ b/readme.md @@ -142,7 +142,7 @@ Everything goes over MQTT (port 1883 of `alex2mqtt.stormysdream.club`); the libr - **Directives.** The directive arrives as JSON on `//alexaDirective`. A directive larger than one TCP segment arrives in fragments, which are put together in one heap block that exists only until `loop()` has parsed it. `loop()` then fires `ReportState` or `Event` (and `DirectiveReceived`, if registered) with the directive: `directive["header"]`, `directive["endpoint"]`, `directive["payload"]`. One directive is handled at a time; a directive that arrives twice (a broker that mirrors its topics delivers every message twice) is handled once. - **Reports.** `send()` publishes the report on `//alexaResponce` at once. The backend waits 7 s for it, so answer from the event handler. Every property carries the board's UTC time as `timeOfSample`. - **Limits.** A directive and a report (or the discovery object of one device) may be 2047 bytes each; `-DALEX2ESP_MAX_DIRECTIVE=` and `-DALEX2ESP_MAX_MESSAGE=` in `build_flags` change that. `send()` returns `false` when the report was not sent: no session with the broker, the MQTT client or the heap cannot take it, or it is too large. Nothing is ever sent truncated, and nothing is dropped without a line on Serial. -- **Serial output.** Every line of the library starts with `[Alex2ESP]`, a problem with `[Alex2ESP] error:`. `alexClient.setLogLevel(AlexaLogLevel::ERROR)` leaves only the problems, `AlexaLogLevel::NONE` nothing; the default, `AlexaLogLevel::INFO`, adds the session, discovery and one line per directive (`[Alex2ESP] ESP-01 <- Alexa.PowerController.TurnOn`). `AlexaLogLevel::DEBUG` (sizes and free heap per message) has to be compiled in with `-DALEX2ESP_LOG_MAX=3`; `-DALEX2ESP_LOG_MAX=0` compiles every line out. Credentials and correlation tokens are never printed. +- **Serial output.** Every line of the library starts with `[Alex2ESP]`, a problem with `[Alex2ESP] error:`. `alexClient.setLogLevel(AlexaLogLevel::ERROR)` leaves only the problems, `AlexaLogLevel::NONE` nothing; the default, `AlexaLogLevel::INFO`, adds the session, discovery and one line per directive (`[Alex2ESP] ESP-01 <- Alexa.PowerController.TurnOn`). `AlexaLogLevel::DEBUG` (sizes and free heap per message) has to be compiled in with `-DALEX2ESP_LOG_MAX=3`; `-DALEX2ESP_LOG_MAX=0` compiles every line out. Credentials and correlation tokens are never printed. A sketch that defines a macro named `DEBUG`, `ERROR` or `INFO` cannot write the level of that name; it passes the number instead, for example `alexClient.setLogLevel(static_cast(3))` for `DEBUG`. Boards that run 1.1.0 or older keep working: the backend still publishes the token on `//alexaDirective_e` and serves the HTTP routes they use. @@ -250,7 +250,7 @@ Behaviour changes: - The subscription delivers the directives of every endpoint of the account. Those for endpoints of another board are recognised by their topic and neither buffered nor parsed. - Discovery is answered from `loop()`, not inside the MQTT callback. A discovery object over 2047 bytes is refused with an error; the other devices are still announced. - `getState()` stays `INITIALIZED` until the first connect, and becomes `CONNECTED` when the broker has acknowledged both subscriptions (1.1.0: the first of them). A refused subscription prints an error. -- Serial output goes through one log with levels. `alexClient.setLogLevel()` takes `AlexaLogLevel::NONE`, `ERROR`, `INFO` (the default) or `DEBUG`; `-DALEX2ESP_LOG_MAX=<0..3>` in `build_flags` sets the highest level that is compiled in (default 2, `INFO`). This replaces the `Alex2ESP_DEBUG` define inside `AlexaUtils.cpp`. 1.1.0 printed the memory figures for every MQTT message and the whole directive, correlation token included, for every directive; both are gone. +- Serial output goes through one log with levels. `alexClient.setLogLevel()` takes `AlexaLogLevel::NONE`, `ERROR`, `INFO` (the default) or `DEBUG`; `-DALEX2ESP_LOG_MAX=<0..3>` in `build_flags` sets the highest level that is compiled in (default 2, `INFO`). This replaces the `Alex2ESP_DEBUG` define inside `AlexaUtils.cpp`. 1.1.0 printed the memory figures for every MQTT message and the whole directive, correlation token included, for every directive; both are gone. A sketch or a build flag that defines `DEBUG`, `ERROR` or `INFO` as a macro (`#define DEBUG 1`, `-DDEBUG`) still compiles: the library sets those macros aside where it declares its levels and passes a level by its number everywhere else. - `getDevice()` before `begin()` prints an error: the device would have no root topic. A second `begin()` is ignored with an error. - New: `Alex2ESP::setLogLevel()`, `Alex2ESP::setTimeSource()`, `AlexaDevice::hasEndpointId()`, `AlexaLog`, `AlexaSendResult`. - Removed: the queues and buffers of `AlexaUtils` (`enqueue`, `dequeue`, `dequeueVals`, `enqueueReceive`, `dequeueReceive`, `isQueueEmpty`, `isQueueFull`, `isReceiveQueueEmpty`, `isReceiveQueueFull`, `receivePayload`, `nextMessageId`) and its `log`/`logln`, which printed nothing unless the library was edited; `AlexaUtils::printMemoryInfo()` stays. `MAX_STATUS_REPORT_SIZE` (the limit is `ALEX2ESP_MAX_MESSAGE`). The library no longer includes `ESP8266HTTPClient`. diff --git a/src/AlexaLog.cpp b/src/AlexaLog.cpp index 460f6d5..71be1f3 100644 --- a/src/AlexaLog.cpp +++ b/src/AlexaLog.cpp @@ -1,6 +1,12 @@ #include "AlexaLog.h" #include +// This file names the levels. A build flag such as -DDEBUG defines its macro here as well (see AlexaLog.h). +#undef NONE +#undef ERROR +#undef INFO +#undef DEBUG + AlexaLogLevel AlexaLog::level = AlexaLogLevel::INFO; Print *AlexaLog::output = &Serial; diff --git a/src/AlexaLog.h b/src/AlexaLog.h index 0e044f8..15c8e86 100644 --- a/src/AlexaLog.h +++ b/src/AlexaLog.h @@ -7,6 +7,20 @@ #include +// DEBUG, ERROR and INFO are names that sketches, build flags and other libraries define as macros ("#define DEBUG 1" +// in front of the includes is a common way to switch a sketch's own prints on). The enumerators are declared with +// those macros set aside, and the macros are put back after them. Code that has such a macro defined cannot spell +// the enumerator of that name; static_cast(3) is the same level. NONE is set aside as well, but a +// project that defines it fails earlier: AsyncMqttClient has an enumerator of that name. +#pragma push_macro("NONE") +#pragma push_macro("ERROR") +#pragma push_macro("INFO") +#pragma push_macro("DEBUG") +#undef NONE +#undef ERROR +#undef INFO +#undef DEBUG + enum class AlexaLogLevel : uint8_t { NONE = 0, // nothing @@ -15,6 +29,11 @@ enum class AlexaLogLevel : uint8_t DEBUG = 3 // sizes and free heap per message; needs ALEX2ESP_LOG_MAX=3 }; +#pragma pop_macro("DEBUG") +#pragma pop_macro("INFO") +#pragma pop_macro("ERROR") +#pragma pop_macro("NONE") + // Highest level that is compiled in: 0 none, 1 ERROR, 2 INFO, 3 DEBUG. Override with -DALEX2ESP_LOG_MAX= in // build_flags. The Arduino IDE has no per-sketch flags and builds with this default. #ifndef ALEX2ESP_LOG_MAX @@ -40,17 +59,21 @@ private: static Print *output; }; -#define ALEX2ESP_LOG(levelNumber, levelName, format, ...) \ - do \ - { \ - if (ALEX2ESP_LOG_MAX >= (levelNumber) && AlexaLog::enabled(levelName)) \ - { \ - AlexaLog::write(levelName, PSTR(format), ##__VA_ARGS__); \ - } \ +// The level is given as its number: these macros expand in every file that logs, also in one that is compiled +// with a DEBUG or ERROR macro of its own, so they must not spell an enumerator. +#define ALEX2ESP_LOG(levelNumber, format, ...) \ + do \ + { \ + if (ALEX2ESP_LOG_MAX >= (levelNumber) && \ + AlexaLog::enabled(static_cast(levelNumber))) \ + { \ + AlexaLog::write(static_cast(levelNumber), \ + PSTR(format), ##__VA_ARGS__); \ + } \ } while (0) -#define ALEX2ESP_LOGE(format, ...) ALEX2ESP_LOG(1, AlexaLogLevel::ERROR, format, ##__VA_ARGS__) -#define ALEX2ESP_LOGI(format, ...) ALEX2ESP_LOG(2, AlexaLogLevel::INFO, format, ##__VA_ARGS__) -#define ALEX2ESP_LOGD(format, ...) ALEX2ESP_LOG(3, AlexaLogLevel::DEBUG, format, ##__VA_ARGS__) +#define ALEX2ESP_LOGE(format, ...) ALEX2ESP_LOG(1, format, ##__VA_ARGS__) +#define ALEX2ESP_LOGI(format, ...) ALEX2ESP_LOG(2, format, ##__VA_ARGS__) +#define ALEX2ESP_LOGD(format, ...) ALEX2ESP_LOG(3, format, ##__VA_ARGS__) #endif // ALEXA_LOG_H