diff --git a/CMakeLists.txt b/CMakeLists.txt index c7c83e1..f528f88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ add_executable(Arduino_WOPR examples/JBWopr_Firmware/JBWopr_Firmware.ino src/ha/ha_abbr.h src/ha/mdi_consts.h + examples/JBWopr_DeviceDemo/secrets.h ) diff --git a/README.md b/README.md index 7573034..4ee6c86 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ -# JBWOPR +# JBWopr + +[![arduino-library-badge](https://www.ardu-badge.com/badge/JBWopr.svg?)](https://www.ardu-badge.com/JBWopr) +![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) JBWopr is a helper library for the Arduino platform that allows you to easily interface with the Unexpected Maker W.O.P.R. board. @@ -39,7 +42,7 @@ that you can also use as a starting point for your own firmware. Full code documentation is available at https://jonnybergdahl.github.io/jbwopr/ -## JBWoprDevicee +## JBWoprDevice Create an instance of the `JBWoprDevice` class. Do any configuration you need to do then and call `begin()` in your `setup()` function. Then call `loop()` in your `loop()` function. @@ -153,7 +156,7 @@ The following settings are available in the web portal: ![MQTT](images/mqttconfig.png "MQTT configuration") -## MQTT Topics +### MQTT Topics At startup, the device will publish an availability message to the `//availability` topic with the payload `online`. It will also set the last will topic to the same topic with the payload `offline`. @@ -162,7 +165,30 @@ You can use that to check if the device is online or not. Current device state is posted to the `///state` topic, it is posted when state is changed. -### Effects +#### Device + +The device will listen to messages on the following topic to restart the device. + +| Topic | Example payload | Comment | +|--------------------------------------------|-----------------|-----------| +| //device/state/set | `restart` | `restart` | + +#### Configuration + +The device will listen to messages on the following topic to change configuration. + +| Topic | Example payload | Comment | +|---------------------------------------------------------|-----------------|--------------------| +| //config/date_format/set | `%Y-%m-%d` | Date format | +| //config/time_format/set | `%H %M %S` | Time format | +| //config/defcon_brightness/set | 50 | DEFCON brightness | +| //config/display_brightness/set | 50 | Display brightness | +| //config/effects_timeout/set | 30 | Effects timeout | +| //config/use_web_portal/set | `True` | Use web portal | + +> The other settings defines the MQTT configuration so can't be set over MQTT. + +#### Effects The device will post a message to the following topics when an effect state is changed. @@ -178,7 +204,7 @@ The device will listen to messages on the following topics. | //effect/state/set | `ON` | `ON` / `OFF` | | //effect/name/set | `Rainbow` | Registered name, will start effect as well | -### Display +#### Display The device will post a message to the following topics when the display state is changed. @@ -198,7 +224,7 @@ The device will listen to command messages on the following topics. | //display/scrolltext/set | `Hello scrolling world` | ASCII characters only | | //display/brightness/set | `50` | `0` to `100` | -### DEFCON LED's +#### DEFCON LED's The device will post a message to the following topics when the DEFCON LED's state is changed. @@ -218,7 +244,7 @@ The device will listen to command messages on the following topics. | //display/brightness/set | `50` | `0` to `100` | | //defcon/color/set | `0,0,128` | RGB byte values in format `R,G,B` | -### Buttons +#### Buttons The device will post a message to the following topics when a button is clicked or double-clicked. @@ -231,72 +257,84 @@ The device will post a message to the following topics when a button is clicked ## JBWoprHomeAssistantDevice -TODO +The `JBWoprHomeAssistantDevice` class adds Home Assistant support to the `JBWoprMqttDevice` class. It will publish +discovery data to the Home Assistant MQTT discovery topic when connected to the MQTT server. -### Topics +When a connection to the MQTT server is established, the device will publish a message to the +`//status` topic with the payload `online`, and also set the last will topic +to the same topic with the payload `offline`. Home Assistant will use that to check if the device is online or not. -| Topic | Example payload | Comment | -|---------------------------------------------|-------------------------|---------------| -| //diagnostics/state | JSON payload, See below | Diagnostics | -| //config/state | JSON payload, See below | Configuration | -| //device/set | JSON payload, See below | Device state | +It will then proceed to publish discovery data to the `///config` topic, +followed by publishing diagnostics and configuration state in the form of JSON messages. It will finally publish +the individual entity states. + +The following settings are available in the web portal: + +![WiFiManager](images/haconfig.png "Home Assistant configuration") + +### Home Assistant + +Once the device has published discovery data to Home Assistant, it will be available under the +MQTT integration. + +If web portal is enabled, the _Visit_ section will be active. + +![Home Assistant Device](images/hadeviceinfo.png "Device info") + +The following entities will be available under _Controls_. + +![Home Assistant Controls](images/hacontrols.png "Controls") + +The following entities will be available under _Configuration_. + +![Home Assistant Configuration](images/haconfiguration.png "Configuration") + +The following entities will be available under _Diagnostics_. + +![Home Assistant Diagnostics](images/hadiagnostics.png "Diagnostics") + +### MQTT Topics + +`JBWoprHomeAssistantDevice` uses the same topics as the `JBWoprMqttDevice` class, and adds the following topics. ### Diagnostics -Diagnostic information is posted at startup. +| Topic | Example payload | Comment | +|---------------------------------------------|-------------------------|---------------| +| //diagnostics/state | JSON payload, See below | Diagnostics | ```json { - "ipAddress": "172.30.2.210", - "rssi": -50, - "version": "1.0.0-beta3" + "ipAddress": "172.30.2.110", + "rssi": -52, + "ram": 201728, + "version": "1.0.0" } - ``` ### Configuration -Current configuration is posted at startup. +| Topic | Example payload | Comment | +|---------------------------------------------|-------------------------|---------------| +| //config/state | JSON payload, See below | Configuration | ```json { - "timeFormat": "%H %M %s", + "timeFormat": "%H %M %S", "dateFormat": "%Y-%m-%d", + "defconBrightness": 50, "displayBrightness": 50, - "defconLedsBrightness": 50, "effectsTimeout": 30, - "wifiHostname": "wopr-5ccf7f2b9b2c", + "hostName": "wopr-461da0d8", "useWebPortal": true, "useMqtt": true, - "mqttServerName": "servername.local", + "mqttServerName": "172.30.2.64", "mqttServerPort": 1883, - "mqttUserName": "username", - "mqttPassword": "password", - "mqttPrefix": "wopr" + "mqttUserName": "user", + "mqttPassword": "pass", + "mqttPrefix": "wopr", + "useHomeAssistant": true, + "discoveryPrefix": "homeassistant" } ``` -### Device state - -Current device state is posted when state is changed. - -```json -{ - "effect": { - "state": "ON", - "name": "Rainbow" - }, - "display": { - "state": "ON", - "text": "Hello World", - "scrollText": "Hello scrolling world", - "brightness": 50 - }, - "defcon": { - "state": "ON", - "level": 1, - "brightness": 50, - "color": "255,0,0" - } -} -``` diff --git a/examples/JBWopr_DeviceDemo/JBWopr_DeviceDemo.ino b/examples/JBWopr_DeviceDemo/JBWopr_DeviceDemo.ino index 8c8d3fe..b8b742f 100644 --- a/examples/JBWopr_DeviceDemo/JBWopr_DeviceDemo.ino +++ b/examples/JBWopr_DeviceDemo/JBWopr_DeviceDemo.ino @@ -5,6 +5,10 @@ // This example shows how to use the JBWoprDevice class to create a simple // device that can display text and scroll text on the display. // +// NOTE: Set your WiFi SSID and Password in the secrets.h file. +// +// Use the left and right buttons to switch between effects. +// // ----------------------------------------------------------------------------- // // JBWopr Library - https://github.com/jonnybergdahl/Arduino_JBWopr_Library @@ -17,7 +21,9 @@ #include #include #include -#include "effects/jbwopreffects.h" +#include +#include +#include #include "secrets.h" #define BOARD_VERSION JBWoprBoardVariant::ORIGINAL @@ -53,7 +59,7 @@ void setup() { config->effectsTimeout = 2; // We are setting log level to max log level - wopr.getLogger()->setLogLevel(LogLevel::LOG_LEVEL_TRACE); + wopr.setLogLevel(LogLevel::LOG_LEVEL_TRACE); // Setting up the devicee wopr.begin(BOARD_VERSION); @@ -90,10 +96,11 @@ void setup() { delay(1000); // Use the JBTimeHelper class to get the local time zone and get the local time + Serial.println("Get time"); wopr.displayShowText("Get time", JBTextAlignment::CENTER); tm timeinfo; if (!JBTimeHelper::getTime(&timeinfo)) { - Serial.println("Failed to obtain time"); + Serial.println("Failed to obtain time - effects that needs time will retry"); wopr.displayShowText("Time failed", JBTextAlignment::CENTER); } } @@ -114,13 +121,13 @@ void loop() { if (resetEffect) { Serial.print("currentEffect: "); Serial.println(currentEffect); - wopr.effectStopCurrent(); + wopr.effectsStopCurrentEffect(); resetEffect = false; startEffect(); } // If we are not running, just display a "pause" text - if (!wopr.effectIsRunning()) + if (!wopr.effectsCurrentEffectIsRunning()) { wopr.displayShowText("<- SWITCH ->"); } @@ -153,34 +160,40 @@ void startEffect() { Serial.printf("Running effect %i: %s for %i ms\n", currentEffect, effect->getName().c_str(), duration); wopr.displayShowText(effect->getName()); delay(1000); - wopr.effectStart(effect, duration); + wopr.effectsStartEffect(effect); } void setupEffects() { // Now we create all effects and put them in a vector // Simple text display - JBWoprTextDisplayEffect* textDisplay = new JBWoprTextDisplayEffect(&wopr); - textDisplay->setText("SOME TEXT"); + JBWoprTextDisplayEffect* textDisplay = new JBWoprTextDisplayEffect(&wopr, "SOME TEXT"); effects.push_back(textDisplay); // Centered text display - textDisplay = new JBWoprTextDisplayEffect(&wopr, JBTextAlignment::CENTER); + textDisplay = new JBWoprTextDisplayEffect(&wopr, "CENTERED", JBTextAlignment::CENTER); textDisplay->setText("CENTERED"); effects.push_back(textDisplay); // Scrolling text effect - JBWoprScrollTextDisplayEffect* scrollTextDisplay = new JBWoprScrollTextDisplayEffect(&wopr); - scrollTextDisplay->setText("This is some scrolling text that is longer than 12 characters"); + JBWoprScrollTextDisplayEffect* scrollTextDisplay = new JBWoprScrollTextDisplayEffect(&wopr, "This is some scrolling text that is longer than 12 characters"); effects.push_back(scrollTextDisplay); // Clock display, time only JBWoprTimeDisplayEffect* timeEffect = new JBWoprTimeDisplayEffect(&wopr); effects.push_back(timeEffect); + // Clock display, time only, with rainbow effect + JBWoprTimeDisplayRainbowEffect* timeRainbowEffect = new JBWoprTimeDisplayRainbowEffect(&wopr); + effects.push_back(timeRainbowEffect); + // Clock display, date only JBWoprDateDisplayEffect* dateEffect = new JBWoprDateDisplayEffect(&wopr); effects.push_back(dateEffect); + // Clock display, date only, with rainbow effect + JBWoprDateDisplayRainbowEffect* dateRainbowEffect = new JBWoprDateDisplayRainbowEffect(&wopr); + effects.push_back(dateRainbowEffect); + // Clock display, time and date JBWoprDateTimeDisplayEffect* dateTimeEffect = new JBWoprDateTimeDisplayEffect(&wopr); effects.push_back(dateTimeEffect); @@ -194,13 +207,11 @@ void setupEffects() { effects.push_back(missileCodeSolve1); // Missile solve effect, message version - JBWoprMissileCodeSolveEffect* missileCodeSolve2 = new JBWoprMissileCodeSolveEffect(&wopr); - missileCodeSolve2->setCodeSolveVariant(CodeSolveVariant::MESSAGE); + JBWoprMissileCodeSolveEffect* missileCodeSolve2 = new JBWoprMissileCodeSolveEffect(&wopr, CodeSolveVariant::MESSAGE, -1, "Msge solve"); effects.push_back(missileCodeSolve2); // Missile solve effect, random version - JBWoprMissileCodeSolveEffect* missileCodeSolve3 = new JBWoprMissileCodeSolveEffect(&wopr); - missileCodeSolve2->setCodeSolveVariant(CodeSolveVariant::RANDOM); + JBWoprMissileCodeSolveEffect* missileCodeSolve3 = new JBWoprMissileCodeSolveEffect(&wopr, CodeSolveVariant::RANDOM, -1, "Rnd solve"); effects.push_back(missileCodeSolve3); // Defcon LED rainbow effect diff --git a/examples/JBWopr_DeviceDemo/secrets.h b/examples/JBWopr_DeviceDemo/secrets.h index ab82c67..875e3cc 100644 --- a/examples/JBWopr_DeviceDemo/secrets.h +++ b/examples/JBWopr_DeviceDemo/secrets.h @@ -5,7 +5,7 @@ #ifndef ARDUINO_WOPR_SECRETS_H #define ARDUINO_WOPR_SECRETS_H -#define WIFI_SSID "PUT SSID HERE"; -#define WIFI_PASSWORD "PUT PASSWORD HERE"; +#define WIFI_SSID "PUT SSID HERE" +#define WIFI_PASSWORD "PUT PASSWORD HERE" #endif //ARDUINO_WOPR_SECRETS_H diff --git a/images/haconfig.png b/images/haconfig.png new file mode 100644 index 0000000..61f383a Binary files /dev/null and b/images/haconfig.png differ diff --git a/images/haconfiguration.png b/images/haconfiguration.png new file mode 100644 index 0000000..4e40cff Binary files /dev/null and b/images/haconfiguration.png differ diff --git a/images/hacontrols.png b/images/hacontrols.png new file mode 100644 index 0000000..604b00c Binary files /dev/null and b/images/hacontrols.png differ diff --git a/images/hadeviceinfo.png b/images/hadeviceinfo.png new file mode 100644 index 0000000..88980f7 Binary files /dev/null and b/images/hadeviceinfo.png differ diff --git a/images/hadiagnostics.png b/images/hadiagnostics.png new file mode 100644 index 0000000..47a628d Binary files /dev/null and b/images/hadiagnostics.png differ diff --git a/src/effects/jbwopreffects.cpp b/src/effects/jbwopreffects.cpp index 3f55e6b..af6109f 100644 --- a/src/effects/jbwopreffects.cpp +++ b/src/effects/jbwopreffects.cpp @@ -838,6 +838,7 @@ void JBWoprSongEffect::loop() { } if (_step >= _song->size()) { +Serial.println("Song done"); _woprDevice->audioClear(); _done = true; _isRunning = false; @@ -847,7 +848,7 @@ void JBWoprSongEffect::loop() { // calculates the duration of each note Note note = _song->at(_step); int32_t divider = note.duration; - uint32_t noteDuration = 0; + uint32_t noteDuration; if (divider == 0) { noteDuration = 0; @@ -860,7 +861,9 @@ void JBWoprSongEffect::loop() { noteDuration *= 1.5; // increases the duration in half for dotted notes } - _woprDevice->audioPlayNote((note_t)note.note, note.octave); + if (note.note != 0) { + _woprDevice->audioPlayNote((note_t)note.note, note.octave); + } std::string text = note.text; diff --git a/src/effects/jbwopreffects.h b/src/effects/jbwopreffects.h index e3cdb5a..5bc6f8c 100644 --- a/src/effects/jbwopreffects.h +++ b/src/effects/jbwopreffects.h @@ -23,7 +23,7 @@ class JBWoprDevice; #define JBWOPR_EFFECT_NAME_TIME "Time" ///< Name of JBWoprDisplayTimeEffect #define JBWOPR_EFFECT_NAME_TIME_RAINBOW "Time R" ///< Name of JBWoprDisplayTimeRainbowEffect #define JBWOPR_EFFECT_NAME_DATE "Date" ///< Name of JBWoprDisplayDateEffect -#define JBWOPR_EFFECT_NAME_DATETIME_RAINBOW "Date Time R" ///< Name of JBWoprDisplayDateTimeRainbowEffect +#define JBWOPR_EFFECT_NAME_DATE_RAINBOW "Date Time R" ///< Name of JBWoprDisplayDateTimeRainbowEffect #define JBWOPR_EFFECT_NAME_DATETIME "Date Time" ///< Name of JBWoprDisplayDateTimeEffect #define JBWOPR_EFFECT_NAME_DATETIME_RAINBOW "Date Time R" ///< Name of JBWoprDisplayDateTimeRainbowEffect #define JBWOPR_EFFECT_NAME_XMAS_SECONDS "Xmas seconds" ///< Name of JBWoprDisplayXmasSecondsEffect @@ -237,7 +237,7 @@ class JBWoprTimeDisplayRainbowEffect : public JBWoprTimeDisplayEffect { explicit JBWoprTimeDisplayRainbowEffect(JBWoprDevice *woprDevice, std::string timeFormat = "", uint32_t duration = -1, - const std::string& name=JBWOPR_EFFECT_NAME_TIME); + const std::string& name=JBWOPR_EFFECT_NAME_TIME_RAINBOW); /// @brief Run loop /// @ingroup EffectGroup @@ -302,7 +302,7 @@ class JBWoprDateDisplayRainbowEffect : public JBWoprDateDisplayEffect { explicit JBWoprDateDisplayRainbowEffect(JBWoprDevice *woprDevice, std::string dateFormat = "", uint32_t duration = -1, - const std::string& name=JBWOPR_EFFECT_NAME_DATE); + const std::string& name=JBWOPR_EFFECT_NAME_DATE_RAINBOW); /// @brief Get name of effect /// @ingroup EffectGroup @@ -379,7 +379,7 @@ class JBWoprDateTimeDisplayRainbowEffect : public JBWoprDateTimeDisplayEffect { std::string timeFormat = "", std::string dateFormat = "", uint32_t duration = -1, - const std::string& name=JBWOPR_EFFECT_NAME_DATETIME); + const std::string& name=JBWOPR_EFFECT_NAME_DATETIME_RAINBOW); /// @brief Get name of effect /// @ingroup EffectGroup diff --git a/src/ha/ha_abbr.h b/src/ha/ha_abbr.h index 6db4ccd..f985665 100644 --- a/src/ha/ha_abbr.h +++ b/src/ha/ha_abbr.h @@ -1,6 +1,11 @@ -// -// Created by Jonny Bergdahl on 2023-11-22. -// +/// @file ha_abbr.h +/// @author Jonny Bergdahl +/// @brief Header file for the JBWopr library +/// @details Contains declarations for the Home Assistant abbreviated discovery names. +/// This code is distributed under the MIT License. See LICENSE for details. +/// @date Created: 2023-10-02 +/// @copyright Copyright© 2023, Jonny Bergdahl +/// /*'act_t': 'action_topic', 'act_tpl': 'action_template', 'atype': 'automation_type', diff --git a/src/ha/mdi_consts.h b/src/ha/mdi_consts.h index 02ac543..6d8147e 100644 --- a/src/ha/mdi_consts.h +++ b/src/ha/mdi_consts.h @@ -1,7 +1,11 @@ -// -// Created by Jonny Bergdahl on 2023-10-16. -// - +/// @file md_consts.h +/// @author Jonny Bergdahl +/// @brief Header file for the JBWopr library +/// @details Contains declarations for Home Assistant icon names. +/// This code is distributed under the MIT License. See LICENSE for details. +/// @date Created: 2023-10-16 +/// @copyright Copyright© 2023, Jonny Bergdahl +/// #ifndef ARDUINO_WOPR_MDI_CONSTS_H #define ARDUINO_WOPR_MDI_CONSTS_H diff --git a/src/jbwopr.cpp b/src/jbwopr.cpp index aaf6bdb..9c71579 100644 --- a/src/jbwopr.cpp +++ b/src/jbwopr.cpp @@ -66,10 +66,6 @@ bool JBWoprDevice::begin(JBWoprBoardVariant variant, JBWoprBoardPins pins) { _woprVariant = variant; _log->info("JBWoprDevice begin, variant: %i", variant); - _defaultEffect = new JBWoprDateTimeDisplayEffect(this, - _config.timeFormat, - _config.dateFormat); - // Buttons _log->trace("Button pins: %i, %i, %i, %i", pins.buttonFrontLeftPin, pins.buttonFrontRightPin, pins.buttonBackTopPin, pins.buttonBackBottomPin); _buttonFrontLeft = new OneButton(pins.buttonFrontLeftPin, false); diff --git a/src/jbwopr.h b/src/jbwopr.h index 6c5c078..78a53c1 100644 --- a/src/jbwopr.h +++ b/src/jbwopr.h @@ -471,37 +471,49 @@ class JBWoprDevice { // Defcon LEDs // Adafruit_NeoPixel _defconLeds = Adafruit_NeoPixel(5, 1, NEO_GRB + NEO_KHZ800); ///< DEFCON LEDs - bool _defconState = true; ///< DEFCON state - JBDefconLevel _defconLevel = JBDefconLevel::DEFCON_NONE; ///< DEFCON level - uint32_t _defconColors[5]; ///< DEFCON colors - uint32_t _defconBrightness = 100; ///< DEFCON brightness - uint32_t _defconLedsColor = 0; ///< DEFCON LED's color + bool _defconState = true; ///< DEFCON state + JBDefconLevel _defconLevel = JBDefconLevel::DEFCON_NONE; ///< DEFCON level + uint32_t _defconColors[5]; ///< DEFCON colors + uint32_t _defconBrightness = 100; ///< DEFCON brightness + uint32_t _defconLedsColor = 0; ///< DEFCON LED's color // Note - due to how Adafruit_Neopixel handles brigthness, we buffer the LED colors into the // _defconPixels variable together with the current brightness value. // We then apply them both before calling show(). uint32_t _defconPixels[5] { 0,0,0,0,0}; ///< DEFCON buffered pixel colors - uint32_t _defconBrigthtness = 100; ///< DEFCON brightness + uint32_t _defconBrigthtness = 100; ///< DEFCON brightness + + /// @brief Get DEFCON level from string value + /// @param value String value + /// @return DEFCON level JBDefconLevel _getDefconLevel(std::string value); + + /// @brief Get DEFCON level string from DEFCON level + /// @param level DEFCON level + /// @return DEFCON level string std::string _getDefconLevelString(JBDefconLevel level); + + /// @brief Get DEFCON LED strip pixel from DEFCON level + /// @param level DEFCON level + /// @return DEFCON LED strip pixel uint32_t _getDefconLedsPixel(JBDefconLevel level); // ==================================================================== // Buttons // - OneButton* _buttonFrontLeft; ///< Front left button - OneButton* _buttonFrontRight; ///< Front right button - OneButton* _buttonBackTop; ///< Back to - OneButton* _buttonBackBottom; ///< Back bottom button - - std::function _buttonFrontLeftClickCallback; ///< Front left button click callback - std::function _buttonFrontLeftDoubleClickCallback; ///< Front left button double click callback - std::function _buttonFrontRightClickCallback; ///< Front right button click callback - std::function _buttonFrontRightDoubleClickCallback; ///< Front right button double click callback - std::function _buttonBackTopClickCallback; ///< Back top button click callback - std::function _buttonBackTopDoubleClickCallback; ///< Back top button double click callback - std::function _buttonBackBottomClickCallback; ///< Back bottom button click callback - std::function _buttonBackBottomDoubleClickCallback; ///< Back bottom button double click callback + OneButton* _buttonFrontLeft; ///< Front left button + OneButton* _buttonFrontRight; ///< Front right button + OneButton* _buttonBackTop; ///< Back to + OneButton* _buttonBackBottom; ///< Back bottom button + + std::function _buttonFrontLeftClickCallback; ///< Front left button click callback + std::function _buttonFrontLeftDoubleClickCallback; ///< Front left button double click callback + std::function _buttonFrontRightClickCallback; ///< Front right button click callback + std::function _buttonFrontRightDoubleClickCallback; ///< Front right button double click callback + std::function _buttonBackTopClickCallback; ///< Back top button click callback + std::function _buttonBackTopDoubleClickCallback; ///< Back top button double click callback + std::function _buttonBackBottomClickCallback; ///< Back bottom button click callback + std::function _buttonBackBottomDoubleClickCallback; ///< Back bottom button double click callback static void _staticButtonFrontLeftClickCallback(void* data); ///< Front left button internal click callback static void _staticButtonFrontLeftDoubleClickCallback(void* data); ///< Front left button internal double click callback diff --git a/src/jbwoprha.cpp b/src/jbwoprha.cpp index aca44f4..451c499 100644 --- a/src/jbwoprha.cpp +++ b/src/jbwoprha.cpp @@ -463,15 +463,7 @@ bool JBWoprHADevice::_homeAssistantPublishState() { mqttPublishMessage(_getTopic(ENTITY_NAME_DEFCON, SUBENTITY_NAME_BRIGHTNESS), std::to_string(_defconBrightness)); mqttPublishMessage(_getTopic(ENTITY_NAME_DEFCON, SUBENTITY_NAME_COLOR), JBStringHelper::rgbToString(_defconLedsColor)); - _log->error("HA State not implemented"); - return false; -} - -void JBWoprHADevice::_homeAssistantHandleCommand(std::string entity, std::string subEntity, std::string command, std::string payload) { - _log->error("HA Command not implemented"); - _log->trace("Home Assistant command: %s/%s/%s:", entity.c_str(), subEntity.c_str(), command.c_str()); - _log->traceDump(payload.c_str(), payload.length()); - + return true; } std::string JBWoprHADevice::_getDiscoveryTopic(const std::string& component, const std::string& prefix, const std::string& entity) { @@ -511,6 +503,9 @@ void JBWoprHADevice::_addDeviceData(DynamicJsonDocument& jsonDoc) { device["manufacturer"] = "Unexpected Maker"; device["model"] = _woprVariant == JBWoprBoardVariant::ORIGINAL ? "W.O.P.R" : "W.O.P.R. Haxorz"; device["sw_version"] = LIBRARY_VERSION; + if (_wifiConfig.useWebPortal) { + device["configuration_url"] = "http://" + WiFi.localIP().toString(); + } } void JBWoprHADevice::_addAvailabilityData(DynamicJsonDocument& jsonDoc) { diff --git a/src/jbwoprha.h b/src/jbwoprha.h index e2a334b..c9c9540 100644 --- a/src/jbwoprha.h +++ b/src/jbwoprha.h @@ -86,14 +86,14 @@ class JBWoprHADevice: public JBWoprMqttDevice { // ==================================================================== // Wifi // - const char* HTML_HOME_ASSISTANT_TITLE = "

Home Assistant settings

"; ///< MQTT title - const char* HTML_CHECKBOX_TRUE = "type=\"checkbox\" checked"; ///< HTML checkbox true - const char* HTML_CHECKBOX_FALSE = "type=\"checkbox\""; ///< HTML checkbox false + const char* HTML_HOME_ASSISTANT_TITLE = "

Home Assistant settings

"; ///< MQTT title + const char* HTML_CHECKBOX_TRUE = "type=\"checkbox\" checked"; ///< HTML checkbox true + const char* HTML_CHECKBOX_FALSE = "type=\"checkbox\""; ///< HTML checkbox false - WiFiManagerParameter* _homeAssistantTitleParam; ///< Home Assistant title - WiFiManagerParameter* _useHomeAssistantParam; ///< Use Home Assistant - WiFiManagerParameter* _homeAssistantDiscoveryPrefixParam; ///< Home Assistant discovery prefix - WiFiManagerParameter* _break3Param; ///< Break + WiFiManagerParameter* _homeAssistantTitleParam; ///< Home Assistant title + WiFiManagerParameter* _useHomeAssistantParam; ///< Use Home Assistant + WiFiManagerParameter* _homeAssistantDiscoveryPrefixParam; ///< Home Assistant discovery prefix + WiFiManagerParameter* _break3Param; ///< Break void _setupWiFiManager() override; void _saveParamsCallback() override; @@ -101,8 +101,8 @@ class JBWoprHADevice: public JBWoprMqttDevice { // ==================================================================== // MQTT // - const char* ENTITY_NAME_DIAGNOSTIC = "diagnostic"; ///< Diagnostics entity name - const char* ENTITY_NAME_CONFIG = "config"; ///< Config entity name + const char* ENTITY_NAME_DIAGNOSTIC = "diagnostic"; ///< Diagnostics entity name + const char* ENTITY_NAME_CONFIG = "config"; ///< Config entity name /// @brief Called when MQTT client get connected /// @ingroup MQTTGroup @@ -112,28 +112,26 @@ class JBWoprHADevice: public JBWoprMqttDevice { // ==================================================================== // Home Assistant // - bool _publishHomeAssistantDiscovery; ///< True if Home Assistant discovery should be published - - const char* HA_DIAG_PREFIX = "diagnostic"; ///< Diagnostic discovery prefix - const char* HA_CONFIG_PREFIX = "config"; ///< Config discovery prefix - - const char* HA_COMPONENT_LIGHT = "light"; ///< Light component - const char* HA_COMPONENT_NUMBER = "number"; ///< Number component - const char* HA_COMPONENT_SELECT = "select"; ///< Select component - const char* HA_COMPONENT_SENSOR = "sensor"; ///< Sensor component - const char* HA_COMPONENT_SWITCH = "switch"; ///< Switch component - const char* HA_COMPONENT_BUTTON = "button"; ///< Button component - - const char* HA_DIAG_ENTITY_IP = "ip"; ///< IP entity name - const char* HA_DIAG_ENTITY_RSSI = "rssi"; ///< RSSI entity name - const char* HA_DIAG_ENTITY_RAM = "ram"; ///< RAM entity name - const char* HA_CONF_ENTITY_DATE_FORMAT = "date_format"; ///< Date format entity name - const char* HA_CONF_ENTITY_TIME_FORMAT = "time_format"; ///< Time format entity name - const char* HA_CONF_ENTITY_DISPLAY_BRIGHTNESS = "display_brightness"; ///< Display brightness entity name - const char* HA_CONF_ENTITY_DEFCON_BRIGHTNESS = "defcon_brightness"; ///< DEFCON brightness entity name - const char* HA_CONF_ENTITY_EFFECTS_TIMEOUT = "effects_timeout"; ///< Effects timeout entity name - const char* HA_CONF_ENTITY_WIFI_USE_WEB_PORTAL = "use_web_portal"; ///< Use web portal entity name - const char* HA_CONF_ENTITY_RESTART = "restart"; ///< Restart entity name + const char* HA_DIAG_PREFIX = "diagnostic"; ///< Diagnostic discovery prefix + const char* HA_CONFIG_PREFIX = "config"; ///< Config discovery prefix + + const char* HA_COMPONENT_LIGHT = "light"; ///< Light component + const char* HA_COMPONENT_NUMBER = "number"; ///< Number component + const char* HA_COMPONENT_SELECT = "select"; ///< Select component + const char* HA_COMPONENT_SENSOR = "sensor"; ///< Sensor component + const char* HA_COMPONENT_SWITCH = "switch"; ///< Switch component + const char* HA_COMPONENT_BUTTON = "button"; ///< Button component + + const char* HA_DIAG_ENTITY_IP = "ip"; ///< IP entity name + const char* HA_DIAG_ENTITY_RSSI = "rssi"; ///< RSSI entity name + const char* HA_DIAG_ENTITY_RAM = "ram"; ///< RAM entity name + const char* HA_CONF_ENTITY_DATE_FORMAT = "date_format"; ///< Date format entity name + const char* HA_CONF_ENTITY_TIME_FORMAT = "time_format"; ///< Time format entity name + const char* HA_CONF_ENTITY_DISPLAY_BRIGHTNESS = "display_brightness"; ///< Display brightness entity name + const char* HA_CONF_ENTITY_DEFCON_BRIGHTNESS = "defcon_brightness"; ///< DEFCON brightness entity name + const char* HA_CONF_ENTITY_EFFECTS_TIMEOUT = "effects_timeout"; ///< Effects timeout entity name + const char* HA_CONF_ENTITY_WIFI_USE_WEB_PORTAL = "use_web_portal"; ///< Use web portal entity name + const char* HA_CONF_ENTITY_RESTART = "restart"; ///< Restart entity name const char* JSON_KEY_HA_DIAG_ENTITY_IP = "ipAddress"; ///< IP entity key name const char* JSON_KEY_HA_DIAG_ENTITY_RSSI = "rssi"; ///< RSSI entity key name @@ -154,10 +152,6 @@ class JBWoprHADevice: public JBWoprMqttDevice { /// @brief Publish Home Assistant state bool _homeAssistantPublishState(); - - /// @brief Handle Home Assistant command - void _homeAssistantHandleCommand(std::string entity, std::string subEntity, std::string command, std::string payload); - /// @brief Get Home Assistant discovery topic /// @param entity Entity /// @param subEntity Sub entity diff --git a/src/jbwoprhelpers.cpp b/src/jbwoprhelpers.cpp index 83863d8..6d46e54 100644 --- a/src/jbwoprhelpers.cpp +++ b/src/jbwoprhelpers.cpp @@ -1,9 +1,15 @@ -#include "jbwoprhelpers.h" +/// @file jbwoprhelpers.cpp +/// @author Jonny Bergdahl +/// @brief Source file for the JBWopr library. +/// @details Contains declarations for the base JBWoprDevice class. +/// This code is distributed under the MIT License. See LICENSE for details. +/// @date Created: 2023-10-02 +/// @copyright Copyright© 2023, Jonny Bergdahl +///#include "jbwoprhelpers.h" #include #include #include - bool JBTimeHelper::_isInitialized = false; uint32_t JBTimeHelper::getUtcOffsetInSeconds() { diff --git a/src/jbwoprhelpers.h b/src/jbwoprhelpers.h index 690dfea..971062f 100644 --- a/src/jbwoprhelpers.h +++ b/src/jbwoprhelpers.h @@ -1,6 +1,6 @@ /// @file timehelper.h /// @author Jonny Bergdahl -/// @brief Main header file for the JBWopr library. +/// @brief Header file for the JBWopr library. /// @details Contains helper class declarations for the JBWopr library. /// This code is distributed under the MIT License. See LICENSE for details. /// @date Created: 2023-10-27 diff --git a/src/jbwoprmqtt.cpp b/src/jbwoprmqtt.cpp index 7301db2..ca474d0 100644 --- a/src/jbwoprmqtt.cpp +++ b/src/jbwoprmqtt.cpp @@ -496,8 +496,13 @@ void JBWoprMqttDevice::_handleConfigCommand(const std::string &subEntity, _config.effectsTimeout = atoi(payload.c_str()); _saveConfiguration(); } else if (subEntity == SUBENTITY_NAME_WIFI_USE_WEB_PORTAL) { - _wifiConfig.useWebPortal = payload == STATE_ON; + _wifiConfig.useWebPortal = payload == "True"; _saveConfiguration(); + if (_wifiConfig.useWebPortal) { + webPortalStart(); + } else { + webPortalStop(); + } } else { _log->error("Unsupported sub entity: %s", subEntity.c_str()); } diff --git a/src/jbwoprmqtt.h b/src/jbwoprmqtt.h index 118074c..1f1a823 100644 --- a/src/jbwoprmqtt.h +++ b/src/jbwoprmqtt.h @@ -308,13 +308,13 @@ class JBWoprMqttDevice: public JBWoprWiFiDevice { // ==================================================================== // Configuration // - JBWoprMqttConfig _mqttConfig; ///< MQTT configuration + JBWoprMqttConfig _mqttConfig; ///< MQTT configuration - const char* JSON_KEY_MQTT_USE_MQTT = "useMqtt"; ///< Use MQTT key name - const char* JSON_KEY_MQTT_SERVER_NAME = "mqttServerName"; ///< MQTT server name key name - const char* JSON_KEY_MQTT_SERVER_PORT = "mqttServerPort"; ///< MQTT server port key name - const char* JSON_KEY_MQTT_USER_NAME = "mqttUserName"; ///< MQTT user name key name - const char* JSON_KEY_MQTT_PASSWORD = "mqttPassword"; ///< MQTT password key name + const char* JSON_KEY_MQTT_USE_MQTT = "useMqtt"; ///< Use MQTT key name + const char* JSON_KEY_MQTT_SERVER_NAME = "mqttServerName"; ///< MQTT server name key name + const char* JSON_KEY_MQTT_SERVER_PORT = "mqttServerPort"; ///< MQTT server port key name + const char* JSON_KEY_MQTT_USER_NAME = "mqttUserName"; ///< MQTT user name key name + const char* JSON_KEY_MQTT_PASSWORD = "mqttPassword"; ///< MQTT password key name const char* JSON_KEY_CONF_MQTT_PREFIX = "mqttPrefix"; ///< MQTT prefix key name /// @brief Set JBWoprMqttDevice specific config values from JSON document @@ -330,20 +330,20 @@ class JBWoprMqttDevice: public JBWoprWiFiDevice { // ==================================================================== // WiFi // - WiFiClient _wifiClient; ///< WiFi client + WiFiClient _wifiClient; / //< WiFi client const char* HTML_MQTT_TITLE = "

MQTT settings

"; ///< MQTT title char _mqttServerPortValue[6]; ///< MQTT server port value // WifiManager parameters - WiFiManagerParameter* _mqttTitleParam; ///< MQTT title WiFiManager parameter - WiFiManagerParameter* _useMqttParam; ///< Use MQTT WiFiManager parameter - WiFiManagerParameter* _mqttServerNameParam; ///< MQTT server name WiFiManager parameter - WiFiManagerParameter* _mqttServerPortParam; ///< MQTT server port WiFiManager parameter - WiFiManagerParameter* _mqttUserNameParam; ///< MQTT user name WiFiManager parameter - WiFiManagerParameter* _mqttPasswordParam; ///< MQTT password WiFiManager parameter - WiFiManagerParameter* _mqttPrefixParam; ///< MQTT prefix WiFiManager parameter - WiFiManagerParameter* _break2Param; ///< Break WiFiManagerparameter + WiFiManagerParameter* _mqttTitleParam; ///< MQTT title WiFiManager parameter + WiFiManagerParameter* _useMqttParam; ///< Use MQTT WiFiManager parameter + WiFiManagerParameter* _mqttServerNameParam; ///< MQTT server name WiFiManager parameter + WiFiManagerParameter* _mqttServerPortParam; ///< MQTT server port WiFiManager parameter + WiFiManagerParameter* _mqttUserNameParam; ///< MQTT user name WiFiManager parameter + WiFiManagerParameter* _mqttPasswordParam; ///< MQTT password WiFiManager parameter + WiFiManagerParameter* _mqttPrefixParam; ///< MQTT prefix WiFiManager parameter + WiFiManagerParameter* _break2Param; ///< Break WiFiManagerparameter /// @brief Setup WiFiManager /// @ingroup WiFiGroup @@ -359,42 +359,42 @@ class JBWoprMqttDevice: public JBWoprWiFiDevice { // ==================================================================== // MQTT // - PubSubClient* _mqttClient; ///< MQTT client - bool _mqttActive = false; ///< MQTT active flag, set tp true after initialization - - const char* ENTITY_NAME_DEVICE = "device"; ///< Device entity name - const char* ENTITY_NAME_CONFIG = "config"; ///< Config entity name - const char* ENTITY_NAME_EFFECT = "effect"; ///< Effect entity name - const char* ENTITY_NAME_DISPLAY = "display"; ///< Display text entity name - const char* ENTITY_NAME_DEFCON = "defcon"; ///< DEFCON LED entity name - const char* ENTITY_NAME_BUTTON_FRONT_LEFT = "button_front_left"; ///< Button front left entity name + PubSubClient* _mqttClient; ///< MQTT client + bool _mqttActive = false; ///< MQTT active flag, set tp true after initialization + + const char* ENTITY_NAME_DEVICE = "device"; ///< Device entity name + const char* ENTITY_NAME_CONFIG = "config"; ///< Config entity name + const char* ENTITY_NAME_EFFECT = "effect"; ///< Effect entity name + const char* ENTITY_NAME_DISPLAY = "display"; ///< Display text entity name + const char* ENTITY_NAME_DEFCON = "defcon"; ///< DEFCON LED entity name + const char* ENTITY_NAME_BUTTON_FRONT_LEFT = "button_front_left"; ///< Button front left entity name const char* ENTITY_NAME_BUTTON_FRONT_RIGHT = "button_front_right"; ///< Button front right entity name - const char* ENTITY_NAME_BUTTON_BACK_TOP = "button_back_top"; ///< Button back top entity name - const char* ENTITY_NAME_BUTTON_BACK_BOTTOM = "button_back_bottom"; ///< Button back bottom entity name - - const char* SUBENTITY_NAME_STATE = "state"; ///< State subentity name - const char* SUBENTITY_NAME_BRIGHTNESS = "brightness"; ///< Brightness subentity name - const char* SUBENTITY_NAME_COLOR = "color"; ///< Color subentity name - const char* SUBENTITY_NAME_TEXT = "text"; ///< Text subentity name - const char* SUBENTITY_NAME_SCROLLTEXT = "scrolltext"; ///< Scroll text subentity name - const char* SUBENTITY_NAME_EVENT = "event"; ///< Event subentity name - const char* SUBENTITY_NAME_LEVEL = "level"; ///< Level subentity name - const char* SUBENTITY_NAME_NAME = "name"; ///< Effect subentity name + const char* ENTITY_NAME_BUTTON_BACK_TOP = "button_back_top"; ///< Button back top entity name + const char* ENTITY_NAME_BUTTON_BACK_BOTTOM = "button_back_bottom"; ///< Button back bottom entity name + + const char* SUBENTITY_NAME_STATE = "state"; ///< State subentity name + const char* SUBENTITY_NAME_BRIGHTNESS = "brightness"; ///< Brightness subentity name + const char* SUBENTITY_NAME_COLOR = "color"; ///< Color subentity name + const char* SUBENTITY_NAME_TEXT = "text"; ///< Text subentity name + const char* SUBENTITY_NAME_SCROLLTEXT = "scrolltext"; ///< Scroll text subentity name + const char* SUBENTITY_NAME_EVENT = "event"; ///< Event subentity name + const char* SUBENTITY_NAME_LEVEL = "level"; ///< Level subentity name + const char* SUBENTITY_NAME_NAME = "name"; ///< Effect subentity name const char* SUBENTITY_NAME_EFFECTS_TIMEOUT = "effects_timeout"; ///< Effects timeout key name const char* SUBENTITY_NAME_TIME_FORMAT = "time_format"; ///< Time format key name const char* SUBENTITY_NAME_DATE_FORMAT = "date_format"; ///< Date Format key name const char* SUBENTITY_NAME_DEFCON_BRIGHTNESS = "defcon_brightness"; ///< DEFCON LEDs brightness key name const char* SUBENTITY_NAME_DISPLAY_BRIGHTNESS = "display_brightness"; ///< Display brightness key name - const char* SUBENTITY_NAME_WIFI_HOST_NAME = "host_name"; ///< Host name key name - const char* SUBENTITY_NAME_WIFI_USE_WEB_PORTAL = "use_web_portal"; ///< Use portal key name + const char* SUBENTITY_NAME_WIFI_HOST_NAME = "host_name"; ///< Host name key name + const char* SUBENTITY_NAME_WIFI_USE_WEB_PORTAL = "use_web_portal"; ///< Use portal key name - const char* STATE_ON = "ON"; ///< State ON - const char* STATE_OFF = "OFF"; ///< State OFF + const char* STATE_ON = "ON"; ///< State ON + const char* STATE_OFF = "OFF"; ///< State OFF - const char* EVENT_CLICK = "click"; ///< Click event - const char* EVENT_DOUBLE_CLICK = "double_click"; ///< Double click event + const char* EVENT_CLICK = "click"; ///< Click event + const char* EVENT_DOUBLE_CLICK = "double_click"; ///< Double click event - const char* COMMAND_SET = "set"; ///< Set command + const char* COMMAND_SET = "set"; ///< Set command /// @brief Start MQTT /// @ingroup MqttGroup diff --git a/src/jbwoprwifi.h b/src/jbwoprwifi.h index f3153e9..39d3bcd 100644 --- a/src/jbwoprwifi.h +++ b/src/jbwoprwifi.h @@ -153,21 +153,21 @@ class JBWoprWiFiDevice: public JBWoprDevice { const char* HTML_CHECKBOX_TRUE = "type=\"checkbox\" checked"; ///< HTML checkbox true const char* HTML_CHECKBOX_FALSE = "type=\"checkbox\""; ///< HTML checkbox false - WiFiManagerParameter* _woprTitleParam; ///< W.O.P.R. title parameter - WiFiManagerParameter* _networkTitleParam; ///< Network title parameter - WiFiManagerParameter* _breakParam; ///< Break parameter - WiFiManagerParameter* _effectsTimeoutParam; ///< Effects timeout parameter - WiFiManagerParameter* _timeFormatParam; ///< Time format parameter - WiFiManagerParameter* _dateFormatParam; ///< Date format parameter - WiFiManagerParameter* _displayBrightnessParam; ///< Display brightness parameter - WiFiManagerParameter* _defconLedsBrightnessParam; ///< DEFCON LEDs brightness parameter - - WiFiManagerParameter* _hostNameParam; ///< Host name parameter - WiFiManagerParameter* _useWebPortalParam; ///< Use web portal parameter - - char _effectsTimeoutValue[3]; ///< Effects timeout value, set in WiFiManager callback - char _defconLedsBrightnessValue[3]; ///< DEFCON LEDs brightness value, set in WiFiManager callback - char _displayBrightnessValue[3]; ///< Display brightness value, set in WiFiManager callback + WiFiManagerParameter* _woprTitleParam; ///< W.O.P.R. title parameter + WiFiManagerParameter* _networkTitleParam; ///< Network title parameter + WiFiManagerParameter* _breakParam; ///< Break parameter + WiFiManagerParameter* _effectsTimeoutParam; ///< Effects timeout parameter + WiFiManagerParameter* _timeFormatParam; ///< Time format parameter + WiFiManagerParameter* _dateFormatParam; ///< Date format parameter + WiFiManagerParameter* _displayBrightnessParam; ///< Display brightness parameter + WiFiManagerParameter* _defconLedsBrightnessParam; ///< DEFCON LEDs brightness parameter + + WiFiManagerParameter* _hostNameParam; ///< Host name parameter + WiFiManagerParameter* _useWebPortalParam; ///< Use web portal parameter + + char _effectsTimeoutValue[3]; ///< Effects timeout value, set in WiFiManager callback + char _defconLedsBrightnessValue[3]; ///< DEFCON LEDs brightness value, set in WiFiManager callback + char _displayBrightnessValue[3]; ///< Display brightness value, set in WiFiManager callback /// @brief Get device name /// @ingroup WiFiGroup