build for esp32 mask project
This commit is contained in:
		
							
								
								
									
										86
									
								
								src/platform/arduino/BluetoothSerialTelemetry.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/platform/arduino/BluetoothSerialTelemetry.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| #include "BluetoothSerialTelemetry.h" | ||||
| #include "../../Static.h" | ||||
| #include "../../Platform.h" | ||||
| #include <ArduinoLog.h> | ||||
| #include "../../inputs/Buttons.h" | ||||
|  | ||||
| #include <cstdlib> | ||||
|  | ||||
| BluetoothSerialTelemetry::BluetoothSerialTelemetry() : InputSource("Bluetooth") | ||||
| { | ||||
|   //m_serial.setPin("0000"); | ||||
|   m_serial.enableSSP(); | ||||
| } | ||||
|  | ||||
| InputEvent | ||||
| BluetoothSerialTelemetry::read() | ||||
| { | ||||
|   bool didRead = false; | ||||
|   while (m_serial.available()) { | ||||
|     didRead = true; | ||||
|     char charRead = m_serial.read(); | ||||
|     m_ringbuf.insert(charRead); | ||||
|     if (charRead == '*') { | ||||
|       static char commandBuf[32]; | ||||
|       size_t cmdSize = m_ringbuf.write(commandBuf); | ||||
|       // Overwrite the '*' character, to leave us with a complete command | ||||
|       commandBuf[cmdSize-1] = 0; | ||||
|  | ||||
|       //Log.notice("Bluetooth read %s", commandBuf); | ||||
|  | ||||
|       if (commandBuf[0] == 'R') { | ||||
|         m_color = CRGB(std::atoi(&commandBuf[1]), m_color.g, m_color.b); | ||||
|         return InputEvent{InputEvent::SetColor, m_color}; | ||||
|       } else if (commandBuf[0] == 'G') { | ||||
|         m_color = CRGB(m_color.r, std::atoi(&commandBuf[1]), m_color.b); | ||||
|         return InputEvent{InputEvent::SetColor, m_color}; | ||||
|       } else if (commandBuf[0] == 'B') { | ||||
|         m_color = CRGB(m_color.r, m_color.g, std::atoi(&commandBuf[1])); | ||||
|         return InputEvent{InputEvent::SetColor, m_color}; | ||||
|       } else if (commandBuf[0] == 'O') { | ||||
|         return InputEvent{InputEvent::UserInput, Buttons::Circle}; | ||||
|       } else if (commandBuf[0] == 'S') { | ||||
|         return InputEvent{InputEvent::UserInput, Buttons::Triangle}; | ||||
|       } else if (commandBuf[0] == 'X') { | ||||
|         return InputEvent{InputEvent::UserInput, Buttons::Cross}; | ||||
|       } else if (commandBuf[0] == '+') { | ||||
|         return InputEvent{InputEvent::SetPower, 1}; | ||||
|       } else if (commandBuf[0] == '-') { | ||||
|         return InputEvent{InputEvent::SetPower, 0}; | ||||
|       } else if (commandBuf[0] == 'p') { | ||||
|         return InputEvent{InputEvent::SetPattern, &commandBuf[1]}; | ||||
|       } else if (commandBuf[0] == 'A') { | ||||
|         char* axisVal = strtok(&commandBuf[1], ","); | ||||
|         const uint8_t accelX = std::atof(axisVal) * 10; | ||||
|         axisVal = strtok(NULL, ","); | ||||
|         const uint8_t accelY = std::atof(axisVal) * 10; | ||||
|         axisVal = strtok(NULL, ","); | ||||
|         const uint8_t accelZ = std::atof(axisVal) * 10; | ||||
|         const uint16_t accelSum = abs(accelX) + abs(accelY) + abs(accelZ); | ||||
|         const uint16_t delta = abs(m_value.value() - accelSum); | ||||
|         m_value.add(accelSum); | ||||
|         if (delta > 32) { | ||||
|           return InputEvent{InputEvent::Acceleration, delta}; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   if (didRead) { | ||||
|     return InputEvent::NetworkActivity; | ||||
|   } else { | ||||
|     return InputEvent{}; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void | ||||
| BluetoothSerialTelemetry::onStart() | ||||
| { | ||||
|   Log.notice("Starting up Bluetooth..."); | ||||
|   if (m_serial.begin(Platform::deviceName())) { | ||||
|     Log.notice("Bluetooth started!"); | ||||
|   } else { | ||||
|     Log.warning("Bluetooth could not be started!"); | ||||
|   } | ||||
| } | ||||
|  | ||||
| STATIC_ALLOC(BluetoothSerialTelemetry); | ||||
							
								
								
									
										41
									
								
								src/platform/arduino/BluetoothSerialTelemetry.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/platform/arduino/BluetoothSerialTelemetry.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| #include <Figments.h> | ||||
| #include <BluetoothSerial.h> | ||||
| #include <Ringbuf.h> | ||||
|  | ||||
| class BluetoothSerialTelemetry : public InputSource { | ||||
|   public: | ||||
|     BluetoothSerialTelemetry(); | ||||
|     void onStart() override; | ||||
|     InputEvent read() override; | ||||
|  | ||||
|     template<typename T, uint8_t Size = 8> | ||||
|     struct Averager { | ||||
|         std::array<T, Size> buf; | ||||
|         unsigned int idx = 0; | ||||
|         unsigned int count = 0; | ||||
|  | ||||
|         void add(const T &value) { | ||||
|             buf[idx] = value; | ||||
|             idx = (idx + 1) % Size; | ||||
|             if (count < Size) { | ||||
|                 count += 1; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         T value() const { | ||||
|             if (count == 0) { | ||||
|                 return T{}; | ||||
|             } | ||||
|             long long int sum = 0; | ||||
|             for(unsigned int i = 0; i < count; i++) { | ||||
|                 sum += buf[i]; | ||||
|             } | ||||
|             return sum / count; | ||||
|         } | ||||
|     }; | ||||
|   private: | ||||
|     BluetoothSerial m_serial; | ||||
|     Ringbuf<char, 32> m_ringbuf; | ||||
|     CRGB m_color; | ||||
|     Averager<int16_t, 32> m_value; | ||||
| }; | ||||
| @@ -1,107 +1,190 @@ | ||||
| #include "MQTTTelemetry.h" | ||||
|  | ||||
| #ifdef BOARD_ESP8266 | ||||
| #include <ESP8266WiFi.h> | ||||
| #elif defined(BOARD_ESP32) | ||||
| #include <WiFi.h> | ||||
| #endif | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
|  | ||||
| #include "../../Static.h" | ||||
| #include "../../Config.h" | ||||
| #include "../../Platform.h" | ||||
|  | ||||
| WiFiClient wifiClient; | ||||
| struct MQTTDevice { | ||||
|   const String id; | ||||
|   const String name; | ||||
|   const String model; | ||||
|   const String softwareVersion; | ||||
|   const String manufacturer; | ||||
|   const String availabilityTopic; | ||||
|  | ||||
|   void toJson(const JsonObject& json) const { | ||||
|     json["name"] = name; | ||||
|     json["mdl"] = model; | ||||
|     json["sw"] = softwareVersion; | ||||
|     json["mf"] = manufacturer; | ||||
|     json["ids"][0] = id; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const String availTopic = String("renderbug/") + Platform::deviceID() + "/availability"; | ||||
|  | ||||
| const MQTTDevice Device{ | ||||
|   Platform::deviceID(), | ||||
|   Platform::deviceName(), | ||||
|   Platform::model(), | ||||
| #ifdef BOARD_ESP8266 | ||||
|   ESP.getSketchMD5(), | ||||
| #else | ||||
|   "", | ||||
| #endif | ||||
|   "Phong Robotics", | ||||
|   availTopic | ||||
| }; | ||||
|  | ||||
| struct MQTTEntity { | ||||
|   const MQTTDevice& device; | ||||
|   String name; | ||||
|   String entityId; | ||||
|   String rootTopic; | ||||
|  | ||||
|   MQTTEntity(const String& domain, const MQTTDevice& device, const String& name) : device(device), name(Platform::deviceName() + " " + name) { | ||||
|     entityId = String(device.id) + "-" + name; | ||||
|     rootTopic = String("homeassistant/") + domain + String("/renderbug/") + entityId; | ||||
|   } | ||||
|  | ||||
|   String configTopic() const { | ||||
|     return rootTopic + "/config"; | ||||
|   } | ||||
|  | ||||
|   String commandTopic() const { | ||||
|     return rootTopic + "/set"; | ||||
|   } | ||||
|  | ||||
|   String heartbeatTopic() const { | ||||
|     return String("renderbug/") + Device.id + "/heartbeat"; | ||||
|   } | ||||
|  | ||||
|   String statTopic() const { | ||||
|     return rootTopic + "/state"; | ||||
|   } | ||||
|  | ||||
|   bool isCommandTopic(const char* topic) const { | ||||
|     if (strncmp(topic, rootTopic.c_str(), rootTopic.length()) == 0) { | ||||
|       return strncmp(&topic[rootTopic.length()], "/set", sizeof("/set")) == 0; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   void toJson(JsonDocument& jsonBuf, bool isInteractive = true) const { | ||||
|     jsonBuf["~"] = rootTopic.c_str(); | ||||
|     jsonBuf["name"] = name; | ||||
|     jsonBuf["unique_id"] = entityId; | ||||
|     if (isInteractive) { | ||||
|       jsonBuf["cmd_t"] = "~/set"; | ||||
|       jsonBuf["ret"] = true; | ||||
|       jsonBuf["schema"] = "json"; | ||||
|     } else { | ||||
|     } | ||||
|     jsonBuf["stat_t"] = "~/state"; | ||||
|     jsonBuf["json_attr_t"] = heartbeatTopic(); | ||||
|     jsonBuf["avty_t"] = device.availabilityTopic; | ||||
|     device.toJson(jsonBuf.createNestedObject("dev")); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const MQTTEntity Lightswitch { | ||||
|   "light", Device, "lightswitch" | ||||
| }; | ||||
|  | ||||
| const MQTTEntity flashlightSwitch { | ||||
|   "switch", Device, "flashlight" | ||||
| }; | ||||
|  | ||||
| const MQTTEntity FPSSensor { | ||||
|   "sensor", Device, "fps" | ||||
| }; | ||||
|  | ||||
| MQTTTelemetry::MQTTTelemetry() : BufferedInputSource("MQTT"), | ||||
|     m_mqtt(PubSubClient(wifiClient)), | ||||
|     m_mqtt(m_wifi), | ||||
|     m_logPrinter(this) | ||||
| {} | ||||
| { | ||||
|     m_debugTopic = String("renderbug/") + Platform::deviceID(); | ||||
| } | ||||
|  | ||||
| void | ||||
| MQTTTelemetry::handleEventOnline(const InputEvent& evt) | ||||
| { | ||||
|   if (!m_mqtt.connected()) { | ||||
|     Log.notice("Connecting to MQTT..."); | ||||
|     const IPAddress server(10, 0, 0, 2); | ||||
|     const char* deviceID = Platform::deviceID(); | ||||
|     Log.verbose("Device ID %s", deviceID); | ||||
|     m_mqtt.setServer(server, 1883); | ||||
|     m_mqtt.setBufferSize(512); | ||||
|     m_mqtt.setCallback(&MQTTTelemetry::s_callback); | ||||
|     if (m_mqtt.connect(deviceID)) { | ||||
|     Log.notice("Connecting to MQTT as %s on %s...", Platform::deviceID(), Device.availabilityTopic.c_str()); | ||||
|     if (m_mqtt.connect(Platform::deviceID(), NULL, NULL, Device.availabilityTopic.c_str(), 0, true, "offline")) { | ||||
|       Log.notice("Connected to MQTT"); | ||||
|       m_needHeartbeat = true; | ||||
|  | ||||
|       const String deviceName = String("Renderbug ESP8266") + (char*)deviceID; | ||||
|       const String rootTopic = String("homeassistant/light/renderbug/") + (char*)deviceID; | ||||
|       const String configTopic = rootTopic + "/config"; | ||||
|       Log.verbose("root topic %s", rootTopic.c_str()); | ||||
|       Log.verbose("config topic %s", configTopic.c_str()); | ||||
|       const String statTopic = rootTopic + "/state"; | ||||
|       const String cmdTopic = rootTopic + "/set"; | ||||
|       const String attrTopic = rootTopic + "/attributes"; | ||||
|       const String logTopic = rootTopic + "/log"; | ||||
|       const String heartbeatTopic = rootTopic + "/heartbeat"; | ||||
|       strcpy(m_statTopic, statTopic.c_str()); | ||||
|       strcpy(m_attrTopic, attrTopic.c_str()); | ||||
|       strcpy(m_cmdTopic, cmdTopic.c_str()); | ||||
|       strcpy(m_logTopic, logTopic.c_str()); | ||||
|       strcpy(m_heartbeatTopic, heartbeatTopic.c_str()); | ||||
|  | ||||
|       StaticJsonDocument<1024> configJson; | ||||
|       configJson["~"] = rootTopic; | ||||
|       configJson["name"] = deviceName; | ||||
|       configJson["ret"] = true; | ||||
|       configJson["unique_id"] = (char*) deviceID; | ||||
|       configJson["cmd_t"] = "~/set"; | ||||
|       configJson["stat_t"] = "~/state"; | ||||
|       configJson["json_attr_t"] = "~/attributes"; | ||||
|       configJson["schema"] = "json"; | ||||
|       configJson["brightness"] = true; | ||||
|       configJson["rgb"] = true; | ||||
|  | ||||
|       Lightswitch.toJson(configJson); | ||||
|  | ||||
|       int i = 0; | ||||
|       for(const Sequencer::Scene& scene : m_sequencer->scenes()) { | ||||
|         configJson["fx_list"][i++] = scene.name; | ||||
|       } | ||||
|       configJson["brightness"] = true; | ||||
|       configJson["rgb"] = true; | ||||
|  | ||||
|       configJson["dev"]["name"] = "Renderbug"; | ||||
| #ifdef PLATFORM_PHOTON | ||||
|       configJson["dev"]["mdl"] = "Photon"; | ||||
| #elif defined(BOARD_ESP32) | ||||
|       configJson["dev"]["mdl"] = "ESP32"; | ||||
| #elif defined(BOARD_ESP8266) | ||||
|       configJson["dev"]["mdl"] = "ESP8266"; | ||||
| #else | ||||
|       configJson["dev"]["mdl"] = "Unknown"; | ||||
| #endif | ||||
|       configJson["dev"]["sw"] = RENDERBUG_VERSION; | ||||
|       configJson["dev"]["mf"] = "Phong Robotics"; | ||||
|       configJson["dev"]["ids"][0] = (char*)deviceID; | ||||
|       char buf[1024]; | ||||
|       serializeJson(configJson, buf, sizeof(buf)); | ||||
|       Log.verbose("Publish %s %s", configTopic.c_str(), buf); | ||||
|       m_mqtt.publish(configTopic.c_str(), buf, true); | ||||
|       m_mqtt.subscribe(m_cmdTopic); | ||||
|  | ||||
|       Log.verbose("Publish %s %s", Lightswitch.configTopic().c_str(), buf); | ||||
|       m_mqtt.publish(Lightswitch.configTopic().c_str(), (uint8_t*)buf, strlen(buf), true); | ||||
|       m_mqtt.subscribe(Lightswitch.commandTopic().c_str()); | ||||
|  | ||||
|       configJson.clear(); | ||||
|       flashlightSwitch.toJson(configJson, false); | ||||
|       configJson["cmd_t"] = "~/set"; | ||||
|       configJson["ret"] = true; | ||||
|       serializeJson(configJson, buf, sizeof(buf)); | ||||
|       m_mqtt.publish(flashlightSwitch.configTopic().c_str(), (uint8_t*)buf, strlen(buf), true); | ||||
|       m_mqtt.subscribe(flashlightSwitch.commandTopic().c_str()); | ||||
|  | ||||
|       configJson.clear(); | ||||
|       FPSSensor.toJson(configJson, false); | ||||
|       configJson["unit_of_meas"] = "Frames/s"; | ||||
|       serializeJson(configJson, buf, sizeof(buf)); | ||||
|  | ||||
|       Log.verbose("Publish %s %s", FPSSensor.configTopic().c_str(), buf); | ||||
|       m_mqtt.publish(FPSSensor.configTopic().c_str(), (uint8_t*)buf, strlen(buf), true); | ||||
|       m_mqtt.subscribe(FPSSensor.commandTopic().c_str()); | ||||
|  | ||||
| #ifdef BOARD_ESP8266 | ||||
|       struct rst_info resetInfo = *ESP.getResetInfoPtr(); | ||||
|       if (resetInfo.reason != 0) { | ||||
|         char buff[200]; | ||||
|         sprintf(&buff[0], "Fatal exception:%d flag:%d (%s) epc1:0x%08x epc2:0x%08x epc3:0x%08x excvaddr:0x%08x depc:0x%08x", resetInfo.exccause, resetInfo.reason, (resetInfo.reason == 0 ? "DEFAULT" : resetInfo.reason == 1 ? "WDT" : resetInfo.reason == 2 ? "EXCEPTION" : resetInfo.reason == 3 ? "SOFT_WDT" : resetInfo.reason == 4 ? "SOFT_RESTART" : resetInfo.reason == 5 ? "DEEP_SLEEP_AWAKE" : resetInfo.reason == 6 ? "EXT_SYS_RST" : "???"), resetInfo.epc1, resetInfo.epc2, resetInfo.epc3, resetInfo.excvaddr, resetInfo.depc);  | ||||
|         Log.warning("Previous crash detected! %s", buff); | ||||
|       } | ||||
| #endif | ||||
|     } else { | ||||
|       Log.warning("Could not connect to MQTT"); | ||||
|     } | ||||
|   } else { | ||||
|     if (evt.intent == InputEvent::SetPower) { | ||||
|     String statTopic = Lightswitch.statTopic(); | ||||
|     if (evt.intent == InputEvent::StopThing && String(evt.asString()) == "Flashlight") { | ||||
|       String flashlightStatTopic = flashlightSwitch.statTopic(); | ||||
|       m_mqtt.publish(flashlightStatTopic.c_str(), "OFF"); | ||||
|     } else if (evt.intent == InputEvent::StartThing && String(evt.asString()) == "Flashlight") { | ||||
|       String flashlightStatTopic = flashlightSwitch.statTopic(); | ||||
|       m_mqtt.publish(flashlightStatTopic.c_str(), "ON"); | ||||
|     } else if (evt.intent == InputEvent::SetPower) { | ||||
|       StaticJsonDocument<256> doc; | ||||
|       char buf[256]; | ||||
|       doc["state"] = evt.asInt() ? "ON" : "OFF"; | ||||
|       m_isOn = evt.asInt() ? true : false; | ||||
|       doc["state"] = m_isOn ? "ON" : "OFF"; | ||||
|       serializeJson(doc, buf, sizeof(buf)); | ||||
|       m_mqtt.publish(m_statTopic, buf); | ||||
|       m_mqtt.publish(statTopic.c_str(), buf); | ||||
|     } else if (evt.intent == InputEvent::SetBrightness) { | ||||
|       StaticJsonDocument<256> doc; | ||||
|       char buf[256]; | ||||
|       doc["brightness"] = evt.asInt(); | ||||
|       doc["state"] = "ON"; | ||||
|       doc["state"] = m_isOn ? "ON" : "OFF"; | ||||
|       serializeJson(doc, buf, sizeof(buf)); | ||||
|       m_mqtt.publish(m_statTopic, buf); | ||||
|       m_mqtt.publish(statTopic.c_str(), buf); | ||||
|     } else if (evt.intent == InputEvent::SetColor) { | ||||
|       StaticJsonDocument<256> doc; | ||||
|       char buf[256]; | ||||
| @@ -109,18 +192,19 @@ MQTTTelemetry::handleEventOnline(const InputEvent& evt) | ||||
|       doc["color"]["r"] = color.r; | ||||
|       doc["color"]["g"] = color.g; | ||||
|       doc["color"]["b"] = color.b; | ||||
|       doc["state"] = "ON"; | ||||
|       doc["state"] = m_isOn ? "ON" : "OFF"; | ||||
|       serializeJson(doc, buf, sizeof(buf)); | ||||
|       m_mqtt.publish(m_statTopic, buf); | ||||
|       m_mqtt.publish(statTopic.c_str(), buf); | ||||
|     } else if (evt.intent == InputEvent::SetPattern) { | ||||
|       StaticJsonDocument<256> doc; | ||||
|       char buf[256]; | ||||
|       doc["effect"] = evt.asString(); | ||||
|       doc["state"] = "ON"; | ||||
|       doc["state"] = m_isOn ? "ON" : "OFF"; | ||||
|       serializeJson(doc, buf, sizeof(buf)); | ||||
|       m_mqtt.publish(m_statTopic, buf); | ||||
|       m_mqtt.publish(statTopic.c_str(), buf); | ||||
|     } else if (evt.intent == InputEvent::FirmwareUpdate) { | ||||
|       m_mqtt.publish("renderbug/debug/firmware", "firmware update!"); | ||||
|       String updateTopic = m_debugTopic + "/firmware"; | ||||
|       m_mqtt.publish(updateTopic.c_str(), "firmware update!"); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -132,6 +216,23 @@ MQTTTelemetry::loop() | ||||
|   OnlineTaskMixin::loop(); | ||||
| } | ||||
|  | ||||
| void | ||||
| MQTTTelemetry::onOnline() | ||||
| { | ||||
|   const IPAddress server(10, 0, 0, 2); | ||||
|  | ||||
|   m_needHeartbeat = true; | ||||
|   m_mqtt.setServer(server, 1883); | ||||
|   m_mqtt.setBufferSize(1024); | ||||
|   m_mqtt.setCallback(&MQTTTelemetry::s_callback); | ||||
| } | ||||
|  | ||||
| void | ||||
| MQTTTelemetry::onOffline() | ||||
| { | ||||
|   m_mqtt.disconnect(); | ||||
| } | ||||
|  | ||||
| void | ||||
| MQTTTelemetry::loopOnline() | ||||
| { | ||||
| @@ -142,89 +243,126 @@ MQTTTelemetry::loopOnline() | ||||
|   if (m_needHeartbeat) { | ||||
|     char buf[512]; | ||||
|     StaticJsonDocument<512> response; | ||||
|     response["fps"] = FastLED.getFPS(); | ||||
|     response["RSSI"] = WiFi.RSSI(); | ||||
|     response["localip"] = WiFi.localIP().toString(); | ||||
|     response["free_ram"] = ESP.getFreeHeap(); | ||||
|     response["os_version"] = ESP.getSdkVersion(); | ||||
|     response["device_id"] = Platform::deviceID(); | ||||
|     response["sketch_version"] = ESP.getSketchMD5(); | ||||
|     response["os_version"] = ESP.getSdkVersion(); | ||||
|     response["localip"] = WiFi.localIP().toString(); | ||||
|     response["pixelCount"] = Static<ConfigService>::instance()->coordMap()->pixelCount; | ||||
|     response["startPixel"] = Static<ConfigService>::instance()->coordMap()->startPixel; | ||||
|     response["RSSI"] = WiFi.RSSI(); | ||||
|     response["free_ram"] = ESP.getFreeHeap(); | ||||
|     response["fps"] = FastLED.getFPS(); | ||||
|     serializeJson(response, buf, sizeof(buf)); | ||||
|     m_mqtt.publish(m_attrTopic, buf); | ||||
|     m_mqtt.publish(m_heartbeatTopic, buf); | ||||
|     Log.notice("Heartbeat: %s", buf); | ||||
|     String availTopic = m_rootTopic + "/available"; | ||||
|     m_mqtt.publish(Lightswitch.heartbeatTopic().c_str(), buf); | ||||
|     m_mqtt.publish(Device.availabilityTopic.c_str(), "online"); | ||||
|     //Log.notice("Heartbeat: %s", buf); | ||||
|  | ||||
|     String fpsCounter = String(FastLED.getFPS()); | ||||
|     m_mqtt.publish(FPSSensor.statTopic().c_str(), fpsCounter.c_str()); | ||||
|  | ||||
|     response.clear(); | ||||
|     auto sched = MainLoop::instance()->scheduler; | ||||
|     for(auto task : sched.tasks) { | ||||
|       response[task->name] = task->state == Task::Running; | ||||
|     } | ||||
|     serializeJson(response, buf, sizeof(buf)); | ||||
|     m_mqtt.publish(m_heartbeatTopic, buf); | ||||
|     m_needHeartbeat = false; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void | ||||
| MQTTTelemetry::callback(char* topic, byte* payload, unsigned int length) | ||||
| MQTTTelemetry::callback(char* topic, const char* payload) | ||||
| { | ||||
|     DynamicJsonDocument doc(1024); | ||||
|     deserializeJson(doc, payload, length); | ||||
|  | ||||
|     if (doc.containsKey("state")) { | ||||
|         if (doc["state"] == "ON") { | ||||
|           setEvent(InputEvent{InputEvent::SetPower, true}); | ||||
|         } else if (doc["state"] == "OFF") { | ||||
|           setEvent(InputEvent{InputEvent::SetPower, false}); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (doc.containsKey("start")) { | ||||
|       strcpy(m_patternBuf, doc["start"].as<const char*>()); | ||||
|       setEvent(InputEvent{InputEvent::StartThing, m_patternBuf}); | ||||
|     } | ||||
|  | ||||
|     if (doc.containsKey("stop")) { | ||||
|       if (doc["stop"] == name) { | ||||
|         Log.notice("You can't kill an idea, or stop the MQTT Task via MQTT."); | ||||
|       } else { | ||||
|         strcpy(m_patternBuf, doc["stop"].as<const char*>()); | ||||
|         setEvent(InputEvent{InputEvent::StopThing, m_patternBuf}); | ||||
|     setEvent(InputEvent::NetworkActivity); | ||||
|     if (flashlightSwitch.isCommandTopic(topic)) { | ||||
|       if (!strncmp((char*)payload, "ON", sizeof("ON"))) { | ||||
|         Log.notice("Turning on flashlight"); | ||||
|         setEvent(InputEvent{InputEvent::SetPower, true}); | ||||
|         setEvent(InputEvent{InputEvent::SetPattern, "Flashlight"}); | ||||
|         setEvent(InputEvent{InputEvent::SetBrightness, 255}); | ||||
|       } else if (!strncmp((char*)payload, "OFF", sizeof("OFF"))) { | ||||
|         Log.notice("Turning off flashlight"); | ||||
|         setEvent(InputEvent{InputEvent::SetPattern, "Idle"}); | ||||
|       } | ||||
|     } | ||||
|     } else if (Lightswitch.isCommandTopic(topic)) { | ||||
|       StaticJsonDocument<512> doc; | ||||
|       deserializeJson(doc, payload); | ||||
|  | ||||
|     if (doc.containsKey("pixelCount")) { | ||||
|       setEvent(InputEvent{InputEvent::SetDisplayLength, (int)doc["pixelCount"]}); | ||||
|     } | ||||
|       if (doc.containsKey("state")) { | ||||
|           if (doc["state"] == "ON") { | ||||
|             Log.notice("Turning on power"); | ||||
|             setEvent(InputEvent{InputEvent::SetPower, true}); | ||||
|           } else if (doc["state"] == "OFF") { | ||||
|             Log.notice("Turning off power"); | ||||
|             setEvent(InputEvent{InputEvent::SetPattern, "Idle"}); | ||||
|             setEvent(InputEvent{InputEvent::SetPower, false}); | ||||
|           } | ||||
|       } | ||||
|  | ||||
|     if (doc.containsKey("startPixel")) { | ||||
|       setEvent(InputEvent{InputEvent::SetDisplayOffset, (int)doc["startPixel"]}); | ||||
|     } | ||||
|       if (doc.containsKey("start")) { | ||||
|         strcpy(m_patternBuf, doc["start"].as<const char*>()); | ||||
|         setEvent(InputEvent{InputEvent::StartThing, m_patternBuf}); | ||||
|       } | ||||
|  | ||||
|     if (doc.containsKey("save")) { | ||||
|       setEvent(InputEvent{InputEvent::SaveConfigurationRequest}); | ||||
|     } | ||||
|       if (doc.containsKey("stop")) { | ||||
|         if (doc["stop"] == name) { | ||||
|           Log.notice("You can't kill an idea, or stop the MQTT Task via MQTT."); | ||||
|         } else { | ||||
|           strcpy(m_patternBuf, doc["stop"].as<const char*>()); | ||||
|           setEvent(InputEvent{InputEvent::StopThing, m_patternBuf}); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|     if (doc.containsKey("effect")) { | ||||
|         strcpy(m_patternBuf, doc["effect"].as<const char*>()); | ||||
|         setEvent(InputEvent{InputEvent::SetPattern, m_patternBuf}); | ||||
|     } | ||||
|       if (doc.containsKey("pixelCount")) { | ||||
|         setEvent(InputEvent{InputEvent::SetDisplayLength, (int)doc["pixelCount"]}); | ||||
|       } | ||||
|  | ||||
|     if (doc.containsKey("color")) { | ||||
|         uint8_t r = doc["color"]["r"]; | ||||
|         uint8_t g = doc["color"]["g"]; | ||||
|         uint8_t b = doc["color"]["b"]; | ||||
|         setEvent(InputEvent{InputEvent::SetColor, CRGB(r, g, b)}); | ||||
|     } | ||||
|       if (doc.containsKey("startPixel")) { | ||||
|         setEvent(InputEvent{InputEvent::SetDisplayOffset, (int)doc["startPixel"]}); | ||||
|       } | ||||
|  | ||||
|     if (doc.containsKey("brightness")) { | ||||
|         setEvent(InputEvent{InputEvent::SetBrightness, (int)doc["brightness"]}); | ||||
|       if (doc.containsKey("save")) { | ||||
|         setEvent(InputEvent{InputEvent::SaveConfigurationRequest}); | ||||
|       } | ||||
|  | ||||
|       if (doc.containsKey("restart")) { | ||||
| #ifdef BOARD_ESP8266 | ||||
|         ESP.wdtDisable(); | ||||
|         ESP.restart(); | ||||
| #endif | ||||
|       } | ||||
|  | ||||
|       if (doc.containsKey("reconnect")) { | ||||
|         m_mqtt.disconnect(); | ||||
|       } | ||||
|  | ||||
|       if (doc.containsKey("ping")) { | ||||
|         m_needHeartbeat = true; | ||||
|         Log.notice("Queuing up heartbeat"); | ||||
|       } | ||||
|  | ||||
|       if (doc.containsKey("effect")) { | ||||
|           strcpy(m_patternBuf, doc["effect"].as<const char*>()); | ||||
|           setEvent(InputEvent{InputEvent::SetPattern, m_patternBuf}); | ||||
|       } | ||||
|  | ||||
|       if (doc.containsKey("color")) { | ||||
|           uint8_t r = doc["color"]["r"]; | ||||
|           uint8_t g = doc["color"]["g"]; | ||||
|           uint8_t b = doc["color"]["b"]; | ||||
|           setEvent(InputEvent{InputEvent::SetColor, CRGB(r, g, b)}); | ||||
|       } | ||||
|  | ||||
|       if (doc.containsKey("brightness")) { | ||||
|           setEvent(InputEvent{InputEvent::SetBrightness, (int)doc["brightness"]}); | ||||
|       } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| MQTTTelemetry::s_callback(char* topic, byte* payload, unsigned int length) | ||||
| { | ||||
|     Static<MQTTTelemetry>::instance()->callback(topic, payload, length); | ||||
|     char topicBuf[128]; | ||||
|     char payloadBuf[512]; | ||||
|     strcpy(topicBuf, topic); | ||||
|     memcpy(payloadBuf, payload, length); | ||||
|     payloadBuf[std::min(sizeof(payloadBuf) - 1, length)] = 0; | ||||
|     Static<MQTTTelemetry>::instance()->callback(topicBuf, payloadBuf); | ||||
| } | ||||
|  | ||||
| STATIC_ALLOC(MQTTTelemetry); | ||||
|   | ||||
| @@ -6,6 +6,13 @@ | ||||
|  | ||||
| #include "../../Sequencer.h" | ||||
|  | ||||
| #ifdef BOARD_ESP8266 | ||||
| #include <ESP8266WiFi.h> | ||||
| #elif defined(BOARD_ESP32) | ||||
| #include <WiFi.h> | ||||
| #endif | ||||
|  | ||||
|  | ||||
| class MQTTTelemetry : public BufferedInputSource, OnlineTaskMixin { | ||||
|   public: | ||||
|     MQTTTelemetry(); | ||||
| @@ -22,7 +29,9 @@ class MQTTTelemetry : public BufferedInputSource, OnlineTaskMixin { | ||||
|           if (byte == '\n') { | ||||
|             size_t bufSize = buf.write(outBuf); | ||||
|             outBuf[std::min(sizeof(outBuf), bufSize)] = 0; | ||||
|             telemetry->m_mqtt.publish(telemetry->m_logTopic, outBuf); | ||||
|             Serial.println(outBuf); | ||||
|             String logTopic = telemetry->m_debugTopic + "/log"; | ||||
|             telemetry->m_mqtt.publish(logTopic.c_str(), outBuf); | ||||
|           } else { | ||||
|             buf.insert(byte); | ||||
|           } | ||||
| @@ -39,20 +48,22 @@ class MQTTTelemetry : public BufferedInputSource, OnlineTaskMixin { | ||||
|  | ||||
|     void loopOnline() override; | ||||
|  | ||||
|   private: | ||||
|     char m_statTopic[100]; | ||||
|     char m_attrTopic[100]; | ||||
|     char m_cmdTopic[100]; | ||||
|     char m_logTopic[100]; | ||||
|     char m_heartbeatTopic[100]; | ||||
|     void onOnline() override; | ||||
|     void onOffline() override; | ||||
|  | ||||
|     void callback(char* topic, byte* payload, unsigned int length); | ||||
|   private: | ||||
|     String m_rootTopic; | ||||
|     String m_debugTopic; | ||||
|  | ||||
|     void callback(char* topic, const char* payload); | ||||
|  | ||||
|     static void s_callback(char* topic, byte* payload, unsigned int length); | ||||
|     char m_patternBuf[48]; | ||||
|     bool m_needHeartbeat = false; | ||||
|     bool m_isOn = true; | ||||
|  | ||||
|     Sequencer *m_sequencer = 0; | ||||
|     WiFiClient m_wifi; | ||||
|     PubSubClient m_mqtt; | ||||
|     LogPrinter m_logPrinter; | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user