Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
52871cc149 | |||
2394f772f4 | |||
02efa8bf24 | |||
a9e13b78c5 | |||
41d3f59207 | |||
5ac3add676 | |||
dae8020ee5 | |||
5e67dc7438 | |||
820aba5fd7 | |||
283016d424 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,4 +4,4 @@
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
|
||||
src/config.h
|
||||
include/config.hpp
|
14
.vscode/settings.json
vendored
Normal file
14
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"array": "cpp",
|
||||
"deque": "cpp",
|
||||
"list": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"vector": "cpp",
|
||||
"string_view": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"ranges": "cpp"
|
||||
},
|
||||
"clang-tidy.checks": ["readability-*", "modernize-*", "bugprone-*"]
|
||||
}
|
3
include/DHTSensor.h
Normal file
3
include/DHTSensor.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
class DHTSensor {}
|
52
include/IRLight.h
Normal file
52
include/IRLight.h
Normal file
@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <IRremoteESP8266.h>
|
||||
#include <IRsend.h>
|
||||
#include <HALightColorTemperatureBrightness.hpp>
|
||||
|
||||
class IRLight: public HALightColorTemperatureBrightnessController {
|
||||
private:
|
||||
bool state;
|
||||
short brightness;
|
||||
byte color_temp;
|
||||
|
||||
IRsend *irsend;
|
||||
|
||||
const uint32_t RDOn = irsend->encodeNEC(0x80, 0x1);
|
||||
|
||||
const uint32_t RDOff = irsend->encodeNEC(0x80, 0x1A);
|
||||
|
||||
const uint32_t RDButtonCenter = irsend->encodeNEC(0x80, 0x5);
|
||||
|
||||
const uint32_t RDBrightnessUp = irsend->encodeNEC(0x80, 0x12);
|
||||
|
||||
const uint32_t RDBrightnessDown = irsend->encodeNEC(0x80, 0x1E);
|
||||
|
||||
const uint32_t RDButtonA = irsend->encodeNEC(0x80, 0x7);
|
||||
|
||||
const uint32_t RDButtonB = irsend->encodeNEC(0x80, 0x8);
|
||||
|
||||
public:
|
||||
explicit IRLight(int pin);
|
||||
explicit IRLight(IRsend *irsend);
|
||||
|
||||
void setState(bool state);
|
||||
bool getState();
|
||||
void on();
|
||||
void off();
|
||||
|
||||
void setBrightness(int brightness);
|
||||
int getBrightness();
|
||||
|
||||
void setColorTemperature(int color);
|
||||
int getColorTemperature();
|
||||
|
||||
void brightnessUp();
|
||||
void brightnessDown();
|
||||
int getBrightnessScale();
|
||||
|
||||
void begin();
|
||||
|
||||
~IRLight();
|
||||
};
|
@ -1,3 +1,7 @@
|
||||
/*
|
||||
* Copyright 2023 Maxim Slipenko
|
||||
*/
|
||||
#pragma once
|
||||
// Настройки WiFi
|
||||
#define WIFI_SSID "SSID_HERE"
|
||||
#define WIFI_PASS "PASS_HERE"
|
||||
@ -11,6 +15,4 @@
|
||||
#define DHTPIN D4 // pin gpio 2 in sensor
|
||||
#define DHTTYPE DHT22 // DHT 22 Change this if you have a DHT11
|
||||
|
||||
#define CLIENT_ID "CLIENT_ID_HERE"
|
||||
#define HUMIDITY_TOPIC "sensor/humidity"
|
||||
#define TEMPERATURE_TOPIC "sensor/temperature"
|
||||
#define HOMEASSISTANT_TOPIC "homeassistant/sensor/sensorDht"
|
6
include/utils.hpp
Normal file
6
include/utils.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
double round2(double value);
|
||||
|
||||
#endif
|
23
lib/HomeAssistantDevices/HAControllableDevice.cpp
Normal file
23
lib/HomeAssistantDevices/HAControllableDevice.cpp
Normal 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);
|
||||
};
|
18
lib/HomeAssistantDevices/HAControllableDevice.hpp
Normal file
18
lib/HomeAssistantDevices/HAControllableDevice.hpp
Normal 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;
|
||||
};
|
40
lib/HomeAssistantDevices/HADevice.cpp
Normal file
40
lib/HomeAssistantDevices/HADevice.cpp
Normal 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");
|
||||
}
|
36
lib/HomeAssistantDevices/HADevice.hpp
Normal file
36
lib/HomeAssistantDevices/HADevice.hpp
Normal 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;
|
||||
};
|
83
lib/HomeAssistantDevices/HALight.cpp
Normal file
83
lib/HomeAssistantDevices/HALight.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
#include <HALight.hpp>
|
||||
|
||||
HALight::HALight(PubSubClient &client, const char *name, const char *unique_id)
|
||||
: HAControllableDevice(client, "light", name, unique_id) {}
|
||||
|
||||
HALight::HALight(PubSubClient &client, const char *name, const char *unique_id,
|
||||
HALightController &baseLight)
|
||||
: HAControllableDevice(client, "light", name, unique_id),
|
||||
light(&baseLight) {}
|
||||
|
||||
JSON_DOCUMENT_TYPE HALight::createConfigJSON() {
|
||||
JSON_DOCUMENT_TYPE doc;
|
||||
|
||||
doc["~"] = device_topic;
|
||||
doc["name"] = name;
|
||||
doc["unique_id"] = unique_id;
|
||||
doc["cmd_t"] = "~/cmd";
|
||||
doc["stat_t"] = "~/state";
|
||||
doc["schema"] = "json";
|
||||
|
||||
patchConfigJSON(doc);
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
JSON_DOCUMENT_TYPE HALight::patchConfigJSON(JSON_DOCUMENT_TYPE &doc) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
JSON_DOCUMENT_TYPE HALight::createStateJSON() {
|
||||
JSON_DOCUMENT_TYPE doc;
|
||||
|
||||
if (light->getState()) {
|
||||
doc["state"] = "ON";
|
||||
} else {
|
||||
doc["state"] = "OFF";
|
||||
}
|
||||
|
||||
patchStateJSON(doc);
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
JSON_DOCUMENT_TYPE HALight::patchStateJSON(JSON_DOCUMENT_TYPE &doc) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
void HALight::innerHandler(const JSON_DOCUMENT_TYPE &doc) {
|
||||
if (strcmp(doc["state"], "ON") == 0) {
|
||||
light->setState(true);
|
||||
} else {
|
||||
light->setState(false);
|
||||
}
|
||||
}
|
||||
|
||||
void HALight::sendState() {
|
||||
JSON_DOCUMENT_TYPE doc = createStateJSON();
|
||||
|
||||
buffer[0] = '\0';
|
||||
serializeJson(doc, buffer, buffer_size);
|
||||
|
||||
Serial.println(state_topic);
|
||||
client.publish(state_topic, buffer, true);
|
||||
}
|
||||
|
||||
void HALight::sendConfig() {
|
||||
JSON_DOCUMENT_TYPE doc = createConfigJSON();
|
||||
buffer[0] = '\0';
|
||||
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;
|
||||
|
||||
JSON_DOCUMENT_TYPE doc;
|
||||
deserializeJson(doc, (const byte *)payload, length);
|
||||
|
||||
innerHandler(doc);
|
||||
|
||||
sendState();
|
||||
}
|
30
lib/HomeAssistantDevices/HALight.hpp
Normal file
30
lib/HomeAssistantDevices/HALight.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <HAControllableDevice.hpp>
|
||||
|
||||
class HALightController {
|
||||
public:
|
||||
virtual void setState(bool state) = 0;
|
||||
virtual bool getState() = 0;
|
||||
};
|
||||
|
||||
#define JSON_DOCUMENT_TYPE StaticJsonDocument<256>
|
||||
|
||||
class HALight : public HAControllableDevice {
|
||||
private:
|
||||
HALightController *light;
|
||||
|
||||
protected:
|
||||
virtual JSON_DOCUMENT_TYPE createConfigJSON();
|
||||
virtual JSON_DOCUMENT_TYPE patchConfigJSON(JSON_DOCUMENT_TYPE &doc);
|
||||
virtual JSON_DOCUMENT_TYPE createStateJSON();
|
||||
virtual JSON_DOCUMENT_TYPE patchStateJSON(JSON_DOCUMENT_TYPE &doc);
|
||||
virtual void innerHandler(const JSON_DOCUMENT_TYPE &doc);
|
||||
HALight(PubSubClient &client, const char *name, const char *unique_id);
|
||||
public:
|
||||
HALight(PubSubClient &client, const char *name, const char *unique_id,
|
||||
HALightController &baseLight);
|
||||
void handle(char *topic, byte *payload, unsigned int length) override;
|
||||
void sendConfig() override;
|
||||
void sendState() override;
|
||||
};
|
30
lib/HomeAssistantDevices/HALightBrightness.cpp
Normal file
30
lib/HomeAssistantDevices/HALightBrightness.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include <HALightBrightness.hpp>
|
||||
|
||||
|
||||
HALightBrightness::HALightBrightness(PubSubClient &client, const char *name, const char *unique_id,
|
||||
HALightBrightnessController &baseLight)
|
||||
: HALight(client, name, unique_id, baseLight), light(&baseLight) {}
|
||||
|
||||
|
||||
JSON_DOCUMENT_TYPE HALightBrightness::patchConfigJSON(JSON_DOCUMENT_TYPE &doc) {
|
||||
doc["brightness"] = true;
|
||||
doc["brightness_scale"] = light->getBrightnessScale();
|
||||
return doc;
|
||||
}
|
||||
|
||||
JSON_DOCUMENT_TYPE HALightBrightness::patchStateJSON(JSON_DOCUMENT_TYPE &doc) {
|
||||
doc["brightness"] = light->getBrightness();
|
||||
return doc;
|
||||
}
|
||||
|
||||
void HALightBrightness::handleBrightness(const JSON_DOCUMENT_TYPE &doc) {
|
||||
if (doc.containsKey("brightness")) {
|
||||
light->setBrightness(doc["brightness"]);
|
||||
}
|
||||
}
|
||||
|
||||
void HALightBrightness::innerHandler(const JSON_DOCUMENT_TYPE &doc) {
|
||||
handleBrightness(doc);
|
||||
delay(50);
|
||||
HALight::innerHandler(doc);
|
||||
}
|
27
lib/HomeAssistantDevices/HALightBrightness.hpp
Normal file
27
lib/HomeAssistantDevices/HALightBrightness.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <HALight.hpp>
|
||||
|
||||
class HALightBrightnessController: public virtual HALightController {
|
||||
public:
|
||||
virtual void setBrightness(int value) = 0;
|
||||
virtual int getBrightness() = 0;
|
||||
|
||||
virtual int getBrightnessScale() = 0;
|
||||
};
|
||||
|
||||
class HALightBrightness : public virtual HALight {
|
||||
private:
|
||||
HALightBrightnessController *light;
|
||||
|
||||
protected:
|
||||
virtual JSON_DOCUMENT_TYPE patchConfigJSON(JSON_DOCUMENT_TYPE &doc) override;
|
||||
virtual JSON_DOCUMENT_TYPE patchStateJSON(JSON_DOCUMENT_TYPE &doc) override;
|
||||
virtual void innerHandler(const JSON_DOCUMENT_TYPE &doc) override;
|
||||
|
||||
void handleBrightness(const JSON_DOCUMENT_TYPE &doc);
|
||||
|
||||
public:
|
||||
HALightBrightness(PubSubClient &client, const char *name, const char *unique_id,
|
||||
HALightBrightnessController &baseLight);
|
||||
};
|
28
lib/HomeAssistantDevices/HALightColorTemperature.cpp
Normal file
28
lib/HomeAssistantDevices/HALightColorTemperature.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include <HALightColorTemperature.hpp>
|
||||
|
||||
HALightColorTemperature::HALightColorTemperature(PubSubClient &client, const char *name, const char *unique_id,
|
||||
HALightColorTemperatureController &baseLight)
|
||||
: HALight(client, "light", name, baseLight),
|
||||
light(&baseLight) {}
|
||||
|
||||
JSON_DOCUMENT_TYPE HALightColorTemperature::patchConfigJSON(JSON_DOCUMENT_TYPE &doc) {
|
||||
doc["color_temp"] = true;
|
||||
return doc;
|
||||
}
|
||||
|
||||
JSON_DOCUMENT_TYPE HALightColorTemperature::patchStateJSON(JSON_DOCUMENT_TYPE &doc) {
|
||||
doc["color_temp"] = light->getColorTemperature();
|
||||
return doc;
|
||||
}
|
||||
|
||||
void HALightColorTemperature::handleColorTemperature(const JSON_DOCUMENT_TYPE &doc) {
|
||||
if (doc.containsKey("color_temp")) {
|
||||
light->setColorTemperature(doc["color_temp"]);
|
||||
}
|
||||
}
|
||||
|
||||
void HALightColorTemperature::innerHandler(const JSON_DOCUMENT_TYPE &doc) {
|
||||
handleColorTemperature(doc);
|
||||
delay(50);
|
||||
HALight::innerHandler(doc);
|
||||
}
|
26
lib/HomeAssistantDevices/HALightColorTemperature.hpp
Normal file
26
lib/HomeAssistantDevices/HALightColorTemperature.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <HALight.hpp>
|
||||
|
||||
class HALightColorTemperatureController: public virtual HALightController {
|
||||
public:
|
||||
virtual void setColorTemperature(int value) = 0;
|
||||
virtual int getColorTemperature() = 0;
|
||||
|
||||
virtual int getBrightnessScale() = 0;
|
||||
};
|
||||
|
||||
class HALightColorTemperature : public virtual HALight {
|
||||
private:
|
||||
HALightColorTemperatureController *light;
|
||||
|
||||
protected:
|
||||
virtual JSON_DOCUMENT_TYPE patchConfigJSON(JSON_DOCUMENT_TYPE &doc) override;
|
||||
virtual JSON_DOCUMENT_TYPE patchStateJSON(JSON_DOCUMENT_TYPE &doc) override;
|
||||
virtual void innerHandler(const JSON_DOCUMENT_TYPE &doc) override;
|
||||
|
||||
void handleColorTemperature(const JSON_DOCUMENT_TYPE &doc);
|
||||
public:
|
||||
HALightColorTemperature(PubSubClient &client, const char *name, const char *unique_id,
|
||||
HALightColorTemperatureController &baseLight);
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
#include <HALightColorTemperatureBrightness.hpp>
|
||||
|
||||
HALightColorTemperatureBrightness::HALightColorTemperatureBrightness(
|
||||
PubSubClient &client,
|
||||
const char *name,
|
||||
const char *unique_id,
|
||||
HALightColorTemperatureBrightnessController &baseLight
|
||||
) :
|
||||
HALightBrightness(client, name, unique_id, baseLight),
|
||||
HALightColorTemperature(client, name, unique_id, baseLight),
|
||||
HALight(client, name, unique_id, baseLight),
|
||||
light(&baseLight)
|
||||
{
|
||||
}
|
||||
|
||||
JSON_DOCUMENT_TYPE HALightColorTemperatureBrightness::patchConfigJSON(JSON_DOCUMENT_TYPE &doc) {
|
||||
HALightBrightness::patchConfigJSON(doc);
|
||||
HALightColorTemperature::patchConfigJSON(doc);
|
||||
return doc;
|
||||
}
|
||||
|
||||
JSON_DOCUMENT_TYPE HALightColorTemperatureBrightness::patchStateJSON(JSON_DOCUMENT_TYPE &doc) {
|
||||
HALightBrightness::patchStateJSON(doc);
|
||||
HALightColorTemperature::patchStateJSON(doc);
|
||||
return doc;
|
||||
}
|
||||
|
||||
void HALightColorTemperatureBrightness::innerHandler(const JSON_DOCUMENT_TYPE &doc) {
|
||||
handleBrightness(doc);
|
||||
delay(50);
|
||||
handleColorTemperature(doc);
|
||||
delay(50);
|
||||
HALight::innerHandler(doc);
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <HALightBrightness.hpp>
|
||||
#include <HALightColorTemperature.hpp>
|
||||
|
||||
class HALightColorTemperatureBrightnessController:
|
||||
public HALightBrightnessController,
|
||||
public HALightColorTemperatureController
|
||||
{
|
||||
};
|
||||
|
||||
class HALightColorTemperatureBrightness :
|
||||
public HALightBrightness,
|
||||
public HALightColorTemperature
|
||||
{
|
||||
private:
|
||||
HALightColorTemperatureBrightnessController *light;
|
||||
|
||||
protected:
|
||||
JSON_DOCUMENT_TYPE patchConfigJSON(JSON_DOCUMENT_TYPE &doc) override;
|
||||
JSON_DOCUMENT_TYPE patchStateJSON(JSON_DOCUMENT_TYPE &doc) override;
|
||||
virtual void innerHandler(const JSON_DOCUMENT_TYPE &doc) override;
|
||||
public:
|
||||
HALightColorTemperatureBrightness(PubSubClient &client, const char *name, const char *unique_id,
|
||||
HALightColorTemperatureBrightnessController &baseLight);
|
||||
};
|
6
lib/HomeAssistantDevices/HomeAssistantDevices.hpp
Normal file
6
lib/HomeAssistantDevices/HomeAssistantDevices.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <HALight.hpp>
|
||||
#include <HALightBrightness.hpp>
|
||||
#include <HALightColorTemperature.hpp>
|
||||
#include <HALightColorTemperatureBrightness.hpp>
|
@ -14,7 +14,13 @@ board = d1_mini_pro
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
adafruit/DHT sensor library@^1.4.3
|
||||
jfturcot/SimpleTimer@0.0.0-alpha+sha.b30890b8f7
|
||||
adafruit/Adafruit Unified Sensor@^1.1.5
|
||||
knolleary/PubSubClient@^2.8
|
||||
bblanchon/ArduinoJson@^6.19.4
|
||||
crankyoldgit/IRremoteESP8266@^2.8.2
|
||||
monitor_speed = 115200
|
||||
monitor_filters = default, esp8266_exception_decoder
|
||||
check_tool = cppcheck, clangtidy
|
||||
check_flags =
|
||||
cppcheck: -v --suppress=*:*/.pio/*
|
||||
clangtidy: --checks=-*,clang-diagnostic-*,-clang-diagnostic-unused-value,clang-analyzer-*,-*,bugprone-*,performance-*,readability-*,-readability-magic-numbers,-readability-braces-around-statements,-readability-inconsistent-declaration-parameter-name,-readability-named-parameter --fix
|
0
src/DHTSensor.cpp
Normal file
0
src/DHTSensor.cpp
Normal file
111
src/IRLight.cpp
Normal file
111
src/IRLight.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
#include <IRLight.h>
|
||||
|
||||
IRLight::IRLight(int pin) {
|
||||
irsend = new IRsend(pin);
|
||||
state = false;
|
||||
}
|
||||
|
||||
IRLight::IRLight(IRsend *irsend) {
|
||||
irsend = irsend;
|
||||
state = false;
|
||||
}
|
||||
|
||||
void IRLight::setState(bool state) {
|
||||
if (state)
|
||||
on();
|
||||
else
|
||||
off();
|
||||
}
|
||||
|
||||
void IRLight::on() {
|
||||
state = true;
|
||||
irsend->sendNEC(RDOn);
|
||||
}
|
||||
|
||||
void IRLight::off() {
|
||||
state = false;
|
||||
irsend->sendNEC(RDOff);
|
||||
}
|
||||
|
||||
void IRLight::setBrightness(int newBrightness) {
|
||||
if (newBrightness > brightness) {
|
||||
for (int i = 0; i < newBrightness - brightness; i++) {
|
||||
brightnessUp();
|
||||
delay(250);
|
||||
}
|
||||
} else if (newBrightness < brightness) {
|
||||
for (int i = 0; i < brightness - newBrightness; i++) {
|
||||
brightnessDown();
|
||||
delay(250);
|
||||
}
|
||||
}
|
||||
brightness = newBrightness;
|
||||
}
|
||||
|
||||
void IRLight::setColorTemperature(int color) {
|
||||
if (color < 208) {
|
||||
color_temp = 2;
|
||||
brightness = 14;
|
||||
irsend->sendNEC(RDButtonB);
|
||||
} else if (color < 294) {
|
||||
color_temp = 1;
|
||||
brightness = 14;
|
||||
irsend->sendNEC(RDButtonCenter);
|
||||
} else {
|
||||
color_temp = 0;
|
||||
brightness = 14;
|
||||
irsend->sendNEC(RDButtonA);
|
||||
}
|
||||
}
|
||||
|
||||
int IRLight::getColorTemperature() {
|
||||
switch (color_temp)
|
||||
{
|
||||
case 0:
|
||||
return 370;
|
||||
case 1:
|
||||
return 262;
|
||||
case 2:
|
||||
return 154;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void IRLight::brightnessUp() {
|
||||
if (brightness < getBrightnessScale()) {
|
||||
brightness++;
|
||||
irsend->sendNEC(RDBrightnessUp);
|
||||
}
|
||||
}
|
||||
|
||||
void IRLight::brightnessDown() {
|
||||
if (brightness > 0) {
|
||||
brightness--;
|
||||
irsend->sendNEC(RDBrightnessDown);
|
||||
}
|
||||
}
|
||||
|
||||
void IRLight::begin() {
|
||||
irsend->begin();
|
||||
brightness = 14;
|
||||
color_temp = 1;
|
||||
irsend->sendNEC(RDButtonCenter);
|
||||
delay(500);
|
||||
off();
|
||||
}
|
||||
|
||||
int IRLight::getBrightnessScale() {
|
||||
return 14;
|
||||
}
|
||||
|
||||
int IRLight::getBrightness() {
|
||||
return brightness;
|
||||
}
|
||||
|
||||
bool IRLight::getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
IRLight::~IRLight() {
|
||||
delete irsend;
|
||||
}
|
23
src/IRLightController.cpp
Normal file
23
src/IRLightController.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#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();
|
||||
}
|
||||
|
||||
void IRLightController::setBrightness(int value) {
|
||||
|
||||
}
|
||||
|
||||
IRLightController::~IRLightController() {}
|
21
src/IRLightController.hpp
Normal file
21
src/IRLightController.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <HomeAssistantDevices.hpp>
|
||||
#include <IRLight.h>
|
||||
|
||||
class IRLightController : public HALightBrightnessController {
|
||||
private:
|
||||
IRLight &irlight;
|
||||
|
||||
public:
|
||||
IRLightController(IRLight &irlight);
|
||||
void begin();
|
||||
void setState(bool state);
|
||||
bool getState();
|
||||
|
||||
void setBrightness(int value);
|
||||
int getBrightness();
|
||||
int getBrightnessScale();
|
||||
|
||||
~IRLightController();
|
||||
};
|
248
src/main.cpp
248
src/main.cpp
@ -1,24 +1,128 @@
|
||||
#include <Arduino.h>
|
||||
/*
|
||||
* Copyright 2023 Maxim Slipenko
|
||||
*/
|
||||
#include <DHT.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <IRLight.h>
|
||||
#include <IRremoteESP8266.h>
|
||||
#include <IRsend.h>
|
||||
#include <PubSubClient.h>
|
||||
|
||||
#include <config.h>
|
||||
#include <HomeAssistantDevices.hpp>
|
||||
#include <IRLightController.hpp>
|
||||
|
||||
#include <config.hpp>
|
||||
#include <utils.hpp>
|
||||
|
||||
static const char ISR_Root_x1[] PROGMEM = R"EOF(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
)EOF";
|
||||
|
||||
BearSSL::X509List certISRG(ISR_Root_x1);
|
||||
BearSSL::WiFiClientSecure espClient;
|
||||
|
||||
WiFiClient espClient;
|
||||
PubSubClient client(espClient);
|
||||
DHT dht(DHTPIN, DHTTYPE);
|
||||
|
||||
void setup_wifi() {
|
||||
IRLight irlight(4);
|
||||
HALightColorTemperatureBrightness halight(client, "light", "l-1", irlight);
|
||||
|
||||
void setup_devices();
|
||||
void setup_wifi();
|
||||
void setup_time();
|
||||
void setup_mqtt();
|
||||
|
||||
void reconnect();
|
||||
|
||||
void mqtt_callback(char *topic, byte *payload, unsigned int length);
|
||||
void mqtt_publish_config();
|
||||
void mqtt_publish_state();
|
||||
void mqtt_subscribe_to_commands();
|
||||
|
||||
float temp;
|
||||
float hum;
|
||||
long lastMsg = 0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
|
||||
setup_devices();
|
||||
setup_wifi();
|
||||
setup_time();
|
||||
setup_mqtt();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (!client.connected())
|
||||
{
|
||||
reconnect();
|
||||
}
|
||||
client.loop();
|
||||
|
||||
/*
|
||||
long now = millis();
|
||||
|
||||
if (now - lastMsg > 60000) {
|
||||
lastMsg = now;
|
||||
temp = round2(dht.readTemperature());
|
||||
|
||||
hum = round2(dht.readHumidity());
|
||||
mqtt_publish_state();
|
||||
}
|
||||
*/
|
||||
delay(100);
|
||||
}
|
||||
|
||||
void setup_devices()
|
||||
{
|
||||
irlight.begin();
|
||||
dht.begin();
|
||||
}
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
delay(10);
|
||||
// We start by connecting to a WiFi network
|
||||
Serial.println();
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(WIFI_SSID);
|
||||
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
@ -27,18 +131,57 @@ void setup_wifi() {
|
||||
Serial.println("WiFi connected");
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
WiFi.setAutoReconnect(true);
|
||||
WiFi.persistent(true);
|
||||
}
|
||||
|
||||
void reconnect() {
|
||||
void setup_time()
|
||||
{
|
||||
configTime(0, 0, "pool.ntp.org");
|
||||
|
||||
Serial.print(F("Waiting for NTP time sync: "));
|
||||
time_t nowSecs = time(nullptr);
|
||||
while (nowSecs < 8 * 3600 * 2)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(F("."));
|
||||
yield();
|
||||
nowSecs = time(nullptr);
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
struct tm timeinfo;
|
||||
gmtime_r(&nowSecs, &timeinfo);
|
||||
Serial.print(F("Current time: "));
|
||||
Serial.print(asctime(&timeinfo));
|
||||
}
|
||||
|
||||
void setup_mqtt()
|
||||
{
|
||||
espClient.setTrustAnchors(&certISRG);
|
||||
|
||||
client.setServer(MQTT_SERVER, MQTT_PORT);
|
||||
client.setCallback(mqtt_callback);
|
||||
|
||||
if (!client.connected())
|
||||
{
|
||||
reconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void reconnect()
|
||||
{
|
||||
// Loop until we're reconnected
|
||||
while (!client.connected()) {
|
||||
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)) {
|
||||
if (client.connect("ESP8266Client", MQTT_LOGIN, MQTT_PASS))
|
||||
{
|
||||
Serial.println("connected");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print("failed, rc=");
|
||||
Serial.print(client.state());
|
||||
Serial.println(" try again in 5 seconds");
|
||||
@ -46,51 +189,46 @@ void reconnect() {
|
||||
delay(5000);
|
||||
}
|
||||
}
|
||||
|
||||
client.subscribe("homeassistant/status");
|
||||
mqtt_publish_config();
|
||||
delay(100);
|
||||
mqtt_publish_state();
|
||||
delay(100);
|
||||
mqtt_subscribe_to_commands();
|
||||
}
|
||||
|
||||
bool checkBound(float newValue, float prevValue, float maxDiff) {
|
||||
return !isnan(newValue) &&
|
||||
(newValue < prevValue - maxDiff || newValue > prevValue + maxDiff);
|
||||
}
|
||||
void mqtt_callback(char *topic, byte *payload, unsigned int length)
|
||||
{
|
||||
Serial.print("Message arrived [");
|
||||
Serial.print(topic);
|
||||
Serial.print("] ");
|
||||
Serial.println();
|
||||
|
||||
long lastMsg = 0;
|
||||
float temp = 0.0;
|
||||
float hum = 0.0;
|
||||
float diff = 1.0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
setup_wifi();
|
||||
client.setServer(MQTT_SERVER, MQTT_PORT);
|
||||
|
||||
dht.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (!client.connected()) {
|
||||
reconnect();
|
||||
}
|
||||
client.loop();
|
||||
|
||||
long now = millis();
|
||||
if (now - lastMsg > 10000) {
|
||||
lastMsg = now;
|
||||
|
||||
float newTemp = dht.readTemperature();
|
||||
float newHum = dht.readHumidity();
|
||||
|
||||
if (checkBound(newTemp, temp, diff)) {
|
||||
temp = newTemp;
|
||||
Serial.print("New temperature:");
|
||||
Serial.println(String(temp).c_str());
|
||||
client.publish(TEMPERATURE_TOPIC, String(temp).c_str(), true);
|
||||
}
|
||||
|
||||
if (checkBound(newHum, hum, diff)) {
|
||||
hum = newHum;
|
||||
Serial.print("New humidity:");
|
||||
Serial.println(String(hum).c_str());
|
||||
client.publish(HUMIDITY_TOPIC, String(hum).c_str(), true);
|
||||
if (strcmp(topic, "homeassistant/status") == 0)
|
||||
{
|
||||
payload[length] = '\0';
|
||||
if (strcmp(reinterpret_cast<char *>(payload), "online") == 0)
|
||||
{
|
||||
Serial.println("Home Assistant is online");
|
||||
mqtt_publish_config();
|
||||
}
|
||||
}
|
||||
|
||||
halight.handle(topic, payload, length);
|
||||
}
|
||||
|
||||
void mqtt_publish_config()
|
||||
{
|
||||
halight.sendConfig();
|
||||
}
|
||||
|
||||
void mqtt_publish_state()
|
||||
{
|
||||
halight.sendState();
|
||||
}
|
||||
|
||||
void mqtt_subscribe_to_commands()
|
||||
{
|
||||
halight.subscribeToCommandTopic();
|
||||
}
|
1
src/utils.cpp
Normal file
1
src/utils.cpp
Normal file
@ -0,0 +1 @@
|
||||
// double round2(double value) { return (int)(value * 100 + 0.5) / 100.0; }
|
Loading…
Reference in New Issue
Block a user