Add LD2410 sensor usermod
This commit is contained in:
		
							
								
								
									
										237
									
								
								usermods/LD2410_v2/usermod_ld2410.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								usermods/LD2410_v2/usermod_ld2410.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,237 @@ | ||||
| #warning **** Included USERMOD_LD2410 **** | ||||
|  | ||||
| #ifndef WLED_ENABLE_MQTT | ||||
| #error "This user mod requires MQTT to be enabled." | ||||
| #endif | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "wled.h" | ||||
| #include <ld2410.h> | ||||
|  | ||||
| class LD2410Usermod : public Usermod { | ||||
|  | ||||
|   private: | ||||
|  | ||||
|     bool enabled = true; | ||||
|     bool initDone = false; | ||||
|     bool sensorFound = false; | ||||
|     unsigned long lastTime = 0; | ||||
|     unsigned long last_mqtt_sent = 0; | ||||
|  | ||||
|     int8_t default_uart_rx = 19; | ||||
|     int8_t default_uart_tx = 18; | ||||
|  | ||||
|  | ||||
|     String mqttMovementTopic = F(""); | ||||
|     String mqttStationaryTopic = F(""); | ||||
|     bool mqttInitialized = false; | ||||
|     bool HomeAssistantDiscovery = true; // Publish Home Assistant Discovery messages | ||||
|  | ||||
|  | ||||
|     ld2410 radar; | ||||
|     bool stationary_detected = false; | ||||
|     bool last_stationary_state = false; | ||||
|     bool movement_detected = false; | ||||
|     bool last_movement_state = false; | ||||
|  | ||||
|     // These config variables have defaults set inside readFromConfig() | ||||
|     int8_t uart_rx_pin; | ||||
|     int8_t uart_tx_pin; | ||||
|  | ||||
|     // string that are used multiple time (this will save some flash memory) | ||||
|     static const char _name[]; | ||||
|     static const char _enabled[]; | ||||
|  | ||||
|     void publishMqtt(const char* topic, const char* state, bool retain); // example for publishing MQTT message | ||||
|  | ||||
|     void _mqttInitialize() | ||||
|     { | ||||
|       mqttMovementTopic = String(mqttDeviceTopic) + F("/ld2410/movement"); | ||||
|       mqttStationaryTopic = String(mqttDeviceTopic) + F("/ld2410/stationary"); | ||||
|       if (HomeAssistantDiscovery){ | ||||
|         _createMqttSensor(F("Movement"), mqttMovementTopic, F("motion"), F("")); | ||||
|         _createMqttSensor(F("Stationary"), mqttStationaryTopic, F("occupancy"), F("")); | ||||
|       }  | ||||
|     } | ||||
|  | ||||
|     // Create an MQTT Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop. | ||||
|     void _createMqttSensor(const String &name, const String &topic, const String &deviceClass, const String &unitOfMeasurement) | ||||
|     { | ||||
|       String t = String(F("homeassistant/binary_sensor/")) + mqttClientID + F("/") + name + F("/config"); | ||||
|        | ||||
|       StaticJsonDocument<600> doc; | ||||
|        | ||||
|       doc[F("name")] = String(serverDescription) + F(" Module"); | ||||
|       doc[F("state_topic")] = topic; | ||||
|       doc[F("unique_id")] = String(mqttClientID) + name; | ||||
|       if (unitOfMeasurement != "") | ||||
|         doc[F("unit_of_measurement")] = unitOfMeasurement; | ||||
|       if (deviceClass != "") | ||||
|         doc[F("device_class")] = deviceClass; | ||||
|       doc[F("expire_after")] = 1800; | ||||
|       doc[F("payload_off")] = "OFF"; | ||||
|       doc[F("payload_on")] = "ON"; | ||||
|  | ||||
|       JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device | ||||
|       device[F("name")] = serverDescription; | ||||
|       device[F("identifiers")] = "wled-sensor-" + String(mqttClientID); | ||||
|       device[F("manufacturer")] = F("WLED"); | ||||
|       device[F("model")] = F("FOSS"); | ||||
|       device[F("sw_version")] = versionString; | ||||
|  | ||||
|       String temp; | ||||
|       serializeJson(doc, temp); | ||||
|       DEBUG_PRINTLN(t); | ||||
|       DEBUG_PRINTLN(temp); | ||||
|  | ||||
|       mqtt->publish(t.c_str(), 0, true, temp.c_str()); | ||||
|     } | ||||
|  | ||||
|   public: | ||||
|  | ||||
|     inline bool isEnabled() { return enabled; } | ||||
|  | ||||
|     void setup() { | ||||
|       Serial1.begin(256000, SERIAL_8N1, uart_rx_pin, uart_tx_pin); | ||||
|       Serial.print(F("\nLD2410 radar sensor initialising: ")); | ||||
|       if(radar.begin(Serial1)){ | ||||
|         Serial.println(F("OK")); | ||||
|       } else { | ||||
|         Serial.println(F("not connected")); | ||||
|       } | ||||
|       initDone = true; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     void loop() { | ||||
|       // NOTE: on very long strips strip.isUpdating() may always return true so update accordingly | ||||
|       if (!enabled || strip.isUpdating()) return; | ||||
|       radar.read(); | ||||
|       unsigned long curr_time = millis(); | ||||
|       if(curr_time - lastTime > 1000)  //Try to Report every 1000ms | ||||
|       { | ||||
|         lastTime = curr_time; | ||||
|         sensorFound = radar.isConnected(); | ||||
|         if(!sensorFound) return; | ||||
|         stationary_detected = radar.presenceDetected(); | ||||
|         if(stationary_detected != last_stationary_state){ | ||||
|           if (WLED_MQTT_CONNECTED){ | ||||
|             publishMqtt("/ld2410/stationary", stationary_detected ? "ON":"OFF", false); | ||||
|             last_stationary_state = stationary_detected; | ||||
|           } | ||||
|         } | ||||
|         movement_detected = radar.movingTargetDetected(); | ||||
|         if(movement_detected != last_movement_state){ | ||||
|           if (WLED_MQTT_CONNECTED){ | ||||
|             publishMqtt("/ld2410/movement", movement_detected ? "ON":"OFF", false); | ||||
|             last_movement_state = movement_detected; | ||||
|           } | ||||
|         } | ||||
|         // If there hasn't been any activity, send current state to confirm sensor is alive | ||||
|         if(curr_time - last_mqtt_sent > 1000*60*5 && WLED_MQTT_CONNECTED){ | ||||
|           publishMqtt("/ld2410/stationary", stationary_detected ? "ON":"OFF", false); | ||||
|           publishMqtt("/ld2410/movement", movement_detected ? "ON":"OFF", false); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     void addToJsonInfo(JsonObject& root) | ||||
|     { | ||||
|       // if "u" object does not exist yet wee need to create it | ||||
|       JsonObject user = root[F("u")]; | ||||
|       if (user.isNull()) user = root.createNestedObject(F("u")); | ||||
|  | ||||
|       JsonArray ld2410_sta_json = user.createNestedArray(F("LD2410 Stationary")); | ||||
|       JsonArray ld2410_mov_json = user.createNestedArray(F("LD2410 Movement")); | ||||
|       if (!enabled){ | ||||
|         ld2410_sta_json.add(F("disabled")); | ||||
|         ld2410_mov_json.add(F("disabled")); | ||||
|       } else if(!sensorFound){ | ||||
|         ld2410_sta_json.add(F("LD2410")); | ||||
|         ld2410_sta_json.add(" Not Found"); | ||||
|       } else { | ||||
|         ld2410_sta_json.add("Sta "); | ||||
|         ld2410_sta_json.add(stationary_detected ? "ON":"OFF"); | ||||
|         ld2410_mov_json.add("Mov "); | ||||
|         ld2410_mov_json.add(movement_detected ? "ON":"OFF"); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     void addToConfig(JsonObject& root) | ||||
|     { | ||||
|       JsonObject top = root.createNestedObject(FPSTR(_name)); | ||||
|       top[FPSTR(_enabled)] = enabled; | ||||
|       //save these vars persistently whenever settings are saved | ||||
|       top["uart_rx_pin"] = default_uart_rx; | ||||
|       top["uart_tx_pin"] = default_uart_tx; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     bool readFromConfig(JsonObject& root) | ||||
|     { | ||||
|       // default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor | ||||
|       // setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed) | ||||
|  | ||||
|       JsonObject top = root[FPSTR(_name)]; | ||||
|  | ||||
|       bool configComplete = !top.isNull(); | ||||
|       if (!configComplete) | ||||
|       { | ||||
|         DEBUG_PRINT(FPSTR(_name)); | ||||
|         DEBUG_PRINT(F("LD2410")); | ||||
|         DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); | ||||
|         return false; | ||||
|       } | ||||
|  | ||||
|       configComplete &= getJsonValue(top["uart_rx_pin"], uart_rx_pin, default_uart_rx); | ||||
|       configComplete &= getJsonValue(top["uart_tx_pin"], uart_tx_pin, default_uart_tx); | ||||
|  | ||||
|       return configComplete; | ||||
|     } | ||||
|  | ||||
|  | ||||
| #ifndef WLED_DISABLE_MQTT | ||||
|     /** | ||||
|      * onMqttConnect() is called when MQTT connection is established | ||||
|      */ | ||||
|     void onMqttConnect(bool sessionPresent) { | ||||
|       // do any MQTT related initialisation here | ||||
|       if(!radar.isConnected()) return; | ||||
|       publishMqtt("/ld2410/status", "I am alive!", false); | ||||
|       if (!mqttInitialized) | ||||
|       { | ||||
|         _mqttInitialize(); | ||||
|         mqttInitialized = true; | ||||
|       } | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     uint16_t getId() | ||||
|     { | ||||
|       return USERMOD_ID_LD2410; | ||||
|     } | ||||
| }; | ||||
|  | ||||
|  | ||||
| // add more strings here to reduce flash memory usage | ||||
| const char LD2410Usermod::_name[]    PROGMEM = "LD2410Usermod"; | ||||
| const char LD2410Usermod::_enabled[] PROGMEM = "enabled"; | ||||
|  | ||||
|  | ||||
| // implementation of non-inline member methods | ||||
|  | ||||
| void LD2410Usermod::publishMqtt(const char* topic, const char* state, bool retain) | ||||
| { | ||||
| #ifndef WLED_DISABLE_MQTT | ||||
|   //Check if MQTT Connected, otherwise it will crash | ||||
|   if (WLED_MQTT_CONNECTED) { | ||||
|     last_mqtt_sent = millis(); | ||||
|     char subuf[64]; | ||||
|     strcpy(subuf, mqttDeviceTopic); | ||||
|     strcat(subuf, topic); | ||||
|     mqtt->publish(subuf, 0, retain, state); | ||||
|   } | ||||
| #endif | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 wesleygas
					wesleygas