начинает создавать библиотеку HA

This commit is contained in:
Maxim Slipenko 2022-06-05 10:14:23 +03:00
parent 283016d424
commit 820aba5fd7
Signed by: Maks1mS
GPG Key ID: 7461AF39A8705FB8
16 changed files with 363 additions and 21 deletions

3
include/DHTSensor.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
class DHTSensor {}

37
include/IRLight.h Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include <IRremoteESP8266.h>
#include <IRsend.h>
class IRLight {
private:
bool state;
IRsend *irsend;
const uint16_t rawDataOn[67] = {
8980, 4420, 580, 520, 630, 470, 630, 520, 580, 520, 630, 470,
630, 520, 580, 520, 630, 1570, 630, 1620, 580, 1620, 630, 1620,
580, 1570, 680, 1570, 630, 1570, 630, 1570, 630, 520, 630, 1570,
630, 470, 630, 520, 630, 470, 630, 470, 630, 470, 680, 470,
630, 470, 630, 520, 630, 1570, 630, 1570, 630, 1620, 630, 1570,
630, 1570, 630, 1570, 680, 1570, 630};
const uint16_t rawDataOff[67] = {
8980, 4370, 680, 420, 730, 420, 680, 420, 680, 420, 730, 420,
680, 420, 680, 420, 730, 1470, 730, 1520, 680, 1520, 730, 1470,
730, 1470, 730, 1520, 680, 1520, 730, 1470, 730, 420, 680, 470,
680, 1470, 730, 420, 680, 1520, 730, 1470, 730, 420, 680, 420,
680, 470, 580, 1620, 630, 470, 630, 1570, 630, 520, 580, 520,
630, 1570, 680, 1520, 730, 1520, 680};
public:
IRLight(int pin);
IRLight(IRsend *irsend);
void on();
void off();
void begin();
bool getState();
~IRLight();
};

View File

@ -0,0 +1,23 @@
#include <HAControllableDevice.hpp>
HAControllableDevice::HAControllableDevice(PubSubClient &client,
const char *device_type,
const char *name,
const char *unique_id)
: HADevice(client, device_type, name, unique_id) {
setupCommandTopic();
}
void HAControllableDevice::setupCommandTopic() {
command_topic_size = strlen(device_topic) + 4 + 1;
command_topic = (char *)malloc(command_topic_size);
strcpy(command_topic, device_topic);
strcat(command_topic, "/cmd");
}
void HAControllableDevice::subscribeToCommandTopic() {
Serial.print("Subscribe to ");
Serial.println(command_topic);
client.subscribe(command_topic);
};

View File

@ -0,0 +1,18 @@
#pragma once
#include <HADevice.hpp>
class HAControllableDevice : public HADevice {
protected:
char *command_topic;
unsigned int command_topic_size;
void setupCommandTopic();
public:
HAControllableDevice(PubSubClient &client, const char *device_type,
const char *name, const char *unique_id);
void subscribeToCommandTopic();
virtual void handle(char *topic, byte *payload, unsigned int length) = 0;
};

View File

@ -0,0 +1,40 @@
#include <HADevice.hpp>
HADevice::HADevice(PubSubClient &client, const char *device_type,
const char *name, const char *unique_id)
: client(client), device_type(device_type), name(name),
unique_id(unique_id) {
buffer = (char *)malloc(MQTT_MAX_PACKET_SIZE);
setupDeviceTopic();
setupConfigTopic();
setupStateTopic();
}
void HADevice::setupDeviceTopic() {
device_topic_size =
strlen(base_topic) + 1 + strlen(device_type) + 1 + strlen(unique_id) + 1;
device_topic = (char *)malloc(device_topic_size);
strcpy(device_topic, base_topic);
strcat(device_topic, "/");
strcat(device_topic, device_type);
strcat(device_topic, "/");
strcat(device_topic, unique_id);
}
void HADevice::setupConfigTopic() {
config_topic_size = strlen(device_topic) + 7 + 1;
config_topic = (char *)malloc(config_topic_size);
strcpy(config_topic, device_topic);
strcat(config_topic, "/config");
}
void HADevice::setupStateTopic() {
state_topic_size = strlen(device_topic) + 6 + 1;
state_topic = (char *)malloc(state_topic_size);
strcpy(state_topic, device_topic);
strcat(state_topic, "/state");
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <ArduinoJson.h>
#include <PubSubClient.h>
class HADevice {
protected:
PubSubClient &client;
const char *name;
const char *unique_id;
const char *device_type;
static constexpr const char *base_topic = "homeassistant";
char *device_topic = nullptr;
unsigned int device_topic_size = 0;
char *config_topic = nullptr;
unsigned int config_topic_size = 0;
char *state_topic = nullptr;
unsigned int state_topic_size = 0;
char *buffer;
unsigned int buffer_size = MQTT_MAX_PACKET_SIZE;
void setupDeviceTopic();
void setupConfigTopic();
void setupStateTopic();
public:
HADevice(PubSubClient &client, const char *device_type, const char *name,
const char *unique_id);
virtual void sendConfig() = 0;
virtual void sendState() = 0;
};

View File

@ -0,0 +1,55 @@
#include <HALight.hpp>
HALight::HALight(PubSubClient &client, const char *name, const char *unique_id,
HALightController &baseLight)
: HAControllableDevice(client, "light", name, unique_id),
light(&baseLight) {}
void HALight::sendState() {
StaticJsonDocument<256> doc;
buffer[0] = '\0';
if (light->getState()) {
doc["state"] = "ON";
} else {
doc["state"] = "OFF";
}
serializeJson(doc, buffer, buffer_size);
Serial.println(state_topic);
client.publish(state_topic, buffer, true);
}
void HALight::sendConfig() {
StaticJsonDocument<256> doc;
buffer[0] = '\0';
doc["~"] = device_topic;
doc["name"] = name;
doc["unique_id"] = unique_id;
doc["cmd_t"] = "~/cmd";
doc["stat_t"] = "~/state";
doc["schema"] = "json";
serializeJson(doc, buffer, buffer_size);
client.publish(config_topic, buffer, true);
}
void HALight::handle(char *topic, byte *payload, unsigned int length) {
if (strcmp(topic, command_topic) != 0)
return;
StaticJsonDocument<256> doc;
deserializeJson(doc, (const byte *)payload, length);
if (strcmp(doc["state"], "ON") == 0) {
light->setState(true);
} else {
light->setState(false);
}
sendState();
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <HAControllableDevice.hpp>
class HALightController {
public:
virtual void setState(bool state) = 0;
virtual bool getState() = 0;
};
class HALight : public HAControllableDevice {
private:
HALightController *light;
public:
HALight(PubSubClient &client, const char *name, const char *unique_id,
HALightController &baseLight);
void handle(char *topic, byte *payload, unsigned int length);
void sendConfig();
void sendState();
};

View File

@ -0,0 +1,3 @@
#pragma once
#include <HALight.hpp>

View File

@ -14,8 +14,8 @@ board = d1_mini_pro
framework = arduino framework = arduino
lib_deps = lib_deps =
adafruit/DHT sensor library@^1.4.3 adafruit/DHT sensor library@^1.4.3
jfturcot/SimpleTimer@0.0.0-alpha+sha.b30890b8f7
adafruit/Adafruit Unified Sensor@^1.1.5 adafruit/Adafruit Unified Sensor@^1.1.5
knolleary/PubSubClient@^2.8 knolleary/PubSubClient@^2.8
bblanchon/ArduinoJson@^6.19.4 bblanchon/ArduinoJson@^6.19.4
crankyoldgit/IRremoteESP8266@^2.8.2
monitor_speed = 115200 monitor_speed = 115200

0
src/DHTSensor.cpp Normal file
View File

27
src/IRLight.cpp Normal file
View File

@ -0,0 +1,27 @@
#include <IRLight.h>
IRLight::IRLight(int pin) {
irsend = new IRsend(pin);
state = false;
}
IRLight::IRLight(IRsend *irsend) {
irsend = irsend;
state = false;
}
void IRLight::on() {
state = true;
irsend->sendRaw(rawDataOn, 67, 38);
}
void IRLight::off() {
state = false;
irsend->sendRaw(rawDataOff, 67, 38);
}
void IRLight::begin() { irsend->begin(); }
bool IRLight::getState() { return state; }
IRLight::~IRLight() { delete irsend; }

17
src/IRLightController.cpp Normal file
View File

@ -0,0 +1,17 @@
#include <IRLightController.hpp>
IRLightController::IRLightController(IRLight &irlight) : irlight(irlight) {}
void IRLightController::begin() { irlight.begin(); };
void IRLightController::setState(bool state) {
if (state) {
irlight.on();
} else {
irlight.off();
}
}
bool IRLightController::getState() { return irlight.getState(); }
IRLightController::~IRLightController() {}

16
src/IRLightController.hpp Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <HomeAssistantDevices.hpp>
#include <IRLight.h>
class IRLightController : public HALightController {
private:
IRLight &irlight;
public:
IRLightController(IRLight &irlight);
void begin();
void setState(bool state);
bool getState();
~IRLightController();
};

View File

@ -1,8 +1,13 @@
#include <Arduino.h>
#include <DHT.h> #include <DHT.h>
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <IRLight.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <PubSubClient.h> #include <PubSubClient.h>
#include <ArduinoJson.h>
#include <HomeAssistantDevices.hpp>
#include <IRLightController.hpp>
#include <config.h> #include <config.h>
#include <utils.h> #include <utils.h>
@ -10,9 +15,14 @@ WiFiClient espClient;
PubSubClient client(espClient); PubSubClient client(espClient);
DHT dht(DHTPIN, DHTTYPE); DHT dht(DHTPIN, DHTTYPE);
IRLight irlight(4);
IRLightController light(irlight);
HALight halight(client, "light", "l-1", light);
void setup_wifi(); void setup_wifi();
void reconnect(); void reconnect();
void mqtt_callback(char* topic, byte* payload, unsigned int length); void mqtt_callback(char *topic, byte *payload, unsigned int length);
void mqtt_publish_config(); void mqtt_publish_config();
void mqtt_publish_state(); void mqtt_publish_state();
@ -33,17 +43,21 @@ void setup() {
if (!client.connected()) { if (!client.connected()) {
reconnect(); reconnect();
} }
client.subscribe("homeassistant/status");
mqtt_publish_config();
dht.begin(); dht.begin();
light.begin();
client.subscribe("homeassistant/status");
halight.subscribeToCommandTopic();
mqtt_publish_config();
if (WiFi.status() == WL_CONNECTED) { if (WiFi.status() == WL_CONNECTED) {
temp = dht.readTemperature(); temp = dht.readTemperature();
hum = dht.readHumidity(); hum = dht.readHumidity();
mqtt_publish_state(); mqtt_publish_state();
halight.sendState();
} }
} }
@ -53,21 +67,34 @@ void loop() {
} }
client.loop(); client.loop();
temp = round2(dht.readTemperature()); long now = millis();
hum = round2(dht.readHumidity());
mqtt_publish_state();
delay(60000); if (now - lastMsg > 60000) {
lastMsg = now;
temp = round2(dht.readTemperature());
hum = round2(dht.readHumidity());
mqtt_publish_state();
}
delay(100);
} }
void mqtt_callback(char* topic, byte* payload, unsigned int length) { void mqtt_callback(char *topic, byte *payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
Serial.println();
if (strcmp(topic, "homeassistant/status") == 0) { if (strcmp(topic, "homeassistant/status") == 0) {
payload[length] = '\0'; payload[length] = '\0';
if (strcmp((char*)payload, "online") == 0) { if (strcmp((char *)payload, "online") == 0) {
Serial.println("Home Assistant is online"); Serial.println("Home Assistant is online");
mqtt_publish_config(); mqtt_publish_config();
} }
} }
halight.handle(topic, payload, length);
} }
void setup_wifi() { void setup_wifi() {
@ -110,33 +137,37 @@ void reconnect() {
} }
void mqtt_publish_config() { void mqtt_publish_config() {
/*
StaticJsonDocument<256> doc; StaticJsonDocument<256> doc;
char buffer[256]; char buffer[256];
doc["device_class"] = "temperature"; doc["device_class"] = "temperature";
doc["name"] = "Temperature"; doc["name"] = "Temperature";
doc["unit_of_meas"] = "°C"; doc["unit_of_meas"] = "°C";
doc["state_topic"] = HOMEASSISTANT_TOPIC"/state"; doc["stat_t"] = HOMEASSISTANT_TOPIC "/state";
doc["value_template"] = "{{value_json.temperature}}"; doc["value_template"] = "{{value_json.temperature}}";
doc["unique_id"] = "t"; doc["unique_id"] = "t";
serializeJson(doc, buffer); serializeJson(doc, buffer);
client.publish(HOMEASSISTANT_TOPIC"/t/config", buffer, true); client.publish(HOMEASSISTANT_TOPIC "/t/config", buffer, true);
doc["device_class"] = "humidity"; doc["device_class"] = "humidity";
doc["name"] = "Humidity"; doc["name"] = "Humidity";
doc["unit_of_meas"] = "%"; doc["unit_of_meas"] = "%";
doc["state_topic"] = HOMEASSISTANT_TOPIC"/state"; doc["stat_t"] = HOMEASSISTANT_TOPIC "/state";
doc["value_template"] = "{{value_json.humidity}}"; doc["value_template"] = "{{value_json.humidity}}";
doc["unique_id"] = "h"; doc["unique_id"] = "h";
serializeJson(doc, buffer); serializeJson(doc, buffer);
client.publish(HOMEASSISTANT_TOPIC"/h/config", buffer, true); client.publish(HOMEASSISTANT_TOPIC "/h/config", buffer, true);
*/
halight.sendConfig();
} }
void mqtt_publish_state() { void mqtt_publish_state() {
/*
Serial.println("===== Sending Data ====="); Serial.println("===== Sending Data =====");
StaticJsonDocument<256> doc; StaticJsonDocument<256> doc;
char buffer[256]; char buffer[256];
@ -149,5 +180,22 @@ void mqtt_publish_state() {
serializeJson(doc, buffer); serializeJson(doc, buffer);
client.publish(HOMEASSISTANT_TOPIC"/state", buffer, true); client.publish(HOMEASSISTANT_TOPIC "/state", buffer, true);
*/
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
// If you do not want to use a username and password, change next line to
// if (client.connect("ESP8266Client")) {
if (client.connect("ESP8266Client", MQTT_LOGIN, MQTT_PASS)) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
} }

View File

@ -1,3 +1 @@
double round2 (double value) { double round2(double value) { return (int)(value * 100 + 0.5) / 100.0; }
return (int)(value * 100 + 0.5) / 100.0;
}