Files
AHome/Kuhnya/src/main.cpp
2025-08-21 11:07:47 +03:00

434 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "main.h"
OneWire oneWire(ONE_WIRE);
DallasTemperature sensors(&oneWire);
BME280I2C bme;
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
BME280::PresUnit presUnit(BME280::PresUnit_Pa);
LiquidCrystal_PCF8574 lcd(0x3F); // set the LCD address to 0x27 for a 16 chars and 2 line display
WiFiClient espClient;
Bounce butt = Bounce();
auto gLed = JLed(GREEN);
float tempC;
char f[4];
void setup() {
pinMode(RED, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(BLUE, OUTPUT);
pinMode(LED_OUT, OUTPUT);
digitalWrite(LED_OUT, LOW);
pinMode(MOVE_S, INPUT);
pinMode(BUTTON, INPUT_PULLUP);
butt.attach(BUTTON);
butt.interval(5); // interval in ms
Wire.begin();
Wire.beginTransmission(0x3F);
int error = Wire.endTransmission();
//Serial.print("Error: ");
//Serial.print(error);
if (error == 0) {
lcd.begin(16, 2); // initialize the lcd
lcd.clear();
lcd.setBacklight(255);
} else {
//Serial.println(": LCD not found.");
} // if
lcd.setCursor(0, 0);
lcd.print("Booting");
WiFi.mode(WIFI_STA);
WiFi.hostname("ESP-Kuh");
ArduinoOTA.onStart([]() { /*Serial.println("Start");*/}); // "Начало OTA-апдейта"
ArduinoOTA.onEnd([]() { /*Serial.println("\nEnd");*/}); // "Завершение OTA-апдейта"
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { /*Serial.printf("Progress: %u%%\r", (progress / (total / 100)));*/ });
ArduinoOTA.onError([](ota_error_t error) {
/*Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); // "Ошибка при аутентификации"
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); // "Ошибка при начале OTA-апдейта"
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); // "Ошибка при подключении"
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); // "Ошибка при получении данных"
else if (error == OTA_END_ERROR) Serial.println("End Failed"); // "Ошибка при завершении OTA-апдейта"*/
});
ArduinoOTA.begin();
bme.begin();
sensors.begin();
sensors.setResolution(12);
sensors.requestTemperatures();
lcd.setCursor(0, 0);
lcd.print("Measure temps...");
delay(1000);
lcd.setCursor(0, 0);
lcd.print("Measure done... ");
tempOut = sensors.getTempC(da[0]);
if (tempOut == DEVICE_DISCONNECTED_C){
tempOut = NAN;
stat[0] = 0;
}
else stat[0] = 1;
tempHol = sensors.getTempC(da[1]);
if (tempHol == DEVICE_DISCONNECTED_C){
tempHol = NAN;
stat[1] = 0;
}
else stat[1] = 1;
tempHoM = sensors.getTempC(da[2]);
if (tempHoM == DEVICE_DISCONNECTED_C){
tempHoM = NAN;
stat[2] = 0;
}
else stat[2] = 1;
tempMor = sensors.getTempC(da[3]);
if (tempMor == DEVICE_DISCONNECTED_C){
tempMor = NAN;
stat[3] = 0;
}
else stat[3] = 1;
EEPROM.begin(64);
EEPROM.get(0, lightData);
lightSP = lightData.SP;
lightDB = lightData.DB;
minCount = 0;
LCDpage = 0;
lightOn = false;
mv = prMV = digitalRead(MOVE_S);
wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect);
wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect);
mqttClient.onConnect(onMqttConnect);
mqttClient.onDisconnect(onMqttDisconnect);
mqttClient.onMessage(onMqttMessage);
mqttClient.setServer(mqtt_server, 1883);
mqttClient.setClientId("ESPKuh");
connectToWifi();
crun = millis();
gLed.Breathe(2000).DelayAfter(1000).MaxBrightness(16).Forever();
}
void loop() {
float tempT(NAN), humT(NAN), pressT(NAN);
// static int gint = 1;
// static bool gdir = true;
ArduinoOTA.handle();
gLed.Update();
butt.update();
if (butt.rose()){
LCDpage++;
if(LCDpage > 3) LCDpage = 0;
showLCD(LCDpage, mv);
}
if((crun + 199) < millis()){
crun = millis();
minCount++;
// if(gdir) gint += 25;
// else gint -= 25;
// if((gint > 499) || (gint < 2)) gdir = !gdir;
// analogWrite(GREEN, gint);
adc = analogRead(A0);
mv = digitalRead(MOVE_S);
if(mv != prMV){
if(mv){
mv = true;
lcd.setBacklight(255);
mqttClient.publish(TOPIC"kuh/move", 1, false, "1");
}
else{
mv = false;
lcd.setBacklight(0);
mqttClient.publish(TOPIC"kuh/move", 1, false, "0");
}
prMV = mv;
}
if((adc > (lightSP + lightDB)) || (mv == false)){
digitalWrite(LED_OUT, LOW);
lightOn = false;
}
if((mv == true) && (adc < lightSP)){
digitalWrite(LED_OUT, HIGH);
lightOn = true;
}
if(((minCount+5) % 10) == 0){ //Once in 2 Second
bme.read(pressT, tempT, humT, tempUnit, presUnit);
if(!isnan(pressT)){
if(!isnan(press)) press += (pressT / 133.322f - press) / 30.0f;
else press = pressT / 133.322f;
}
if(!isnan(tempT)){
if(!isnan(tempIn)) tempIn += (tempT - tempIn) / 30.0f;
else tempIn = tempT;
}
if(!isnan(humT)){
if(!isnan(hum)) hum += (humT - hum) / 30.0f;
else hum = humT;
}
}
if (minCount == 300){ //Once in Minute
lcd.begin(16, 2);
publishMin();
minCount = 0;
}
if((minCount % 5) == 0){ //Once in Second
getTemp();
//digitalWrite(GREEN, !digitalRead(GREEN));
//publishSec();
showLCD(LCDpage, mv);
}
}
}
void showLCD(int page, bool l_on)
{
char outS[20];
switch (page)
{
case 0:
lcd.setCursor(0, 0);
lcd.printf("O:%5.1fC I:%4.1fC ", tempOut, tempIn);
lcd.setCursor(0, 1);
lcd.printf("H:%4.1f%% Pr:%3.0fmm", hum, press);
break;
case 1:
lcd.setCursor(0, 0);
lcd.printf("H:%4.1fC M:%5.1fC ", tempHol, tempHoM);
lcd.setCursor(0, 1);
lcd.printf("Mor:%5.1fC ", tempMor);
break;
case 2:
lcd.setCursor(0, 0);
lcd.printf("L: %3d SP: %3d ", adc, lightSP);
lcd.print(outS);
lcd.setCursor(0, 1);
lcd.printf("DB: %2u MS: %1u L:%1d", lightDB, mv, lightOn);
break;
case 3:
lcd.setCursor(0, 0);
lcd.printf("T1:%d T2:%d %d", stat[0], stat[1], nSens);
lcd.setCursor(0, 1);
lcd.printf("T3:%d T4:%d %3d", stat[2], stat[3], WiFi.RSSI());
break;
default:
break;
}
}
void publishSec()
{
/* digitalWrite(GREEN, HIGH);
dtostrf(tempOut, 6, 1, strFVal);
mqttClient.publish("/hometest/kuh1s/temp_out", 1, false, strFVal);
dtostrf(tempIn, 6, 1, strFVal);
mqttClient.publish("/hometest/kuh1s/temp_in", 1, false, strFVal);
dtostrf(hum, 6, 1, strFVal);
mqttClient.publish("/hometest/kuh1s/humidity", 1, false, strFVal);
dtostrf(press, 6, 1, strFVal);
mqttClient.publish("/hometest/kuh1s/pressure", 1, false, strFVal);
itoa(adc, strFVal, 10);
mqttClient.publish("/hometest/kuh1s/light_cur", 1, false, strFVal);
dtostrf(tempHol, 6, 1, strFVal);
mqttClient.publish("/hometest/kuh1s/hol_top", 1, false, strFVal);
dtostrf(tempHoM, 6, 1, strFVal);
mqttClient.publish("/hometest/kuh1s/hol_down", 1, false, strFVal);
dtostrf(tempMor, 6, 1, strFVal);
mqttClient.publish("/hometest/kuh1s/moroz", 1, false, strFVal);
itoa(crun, strFVal, 10);
mqttClient.publish("/hometest/kuh1s/millis", 1, false, strFVal);
digitalWrite(GREEN, LOW);*/
}
void publishMin()
{
digitalWrite(BLUE, HIGH);
if(!isnan(tempOut)){
dtostrf(tempOut, 6, 1, strFVal);
trim(strFVal);
mqttClient.publish(TOPIC"kuh/temp_out", 1, false, strFVal);
}
if(!isnan(tempIn)){
dtostrf(tempIn, 6, 1, strFVal);
trim(strFVal);
mqttClient.publish(TOPIC"kuh/temp_in", 1, false, strFVal);
}
if(!isnan(hum)){
dtostrf(hum, 6, 1, strFVal);
trim(strFVal);
mqttClient.publish(TOPIC"kuh/humidity", 1, false, strFVal);
}
if(!isnan(press)){
dtostrf(press, 6, 1, strFVal);
trim(strFVal);
mqttClient.publish(TOPIC"kuh/pressure", 1, false, strFVal);
}
//itoa(lightSP, strFVal, 10);
//mqttClient.publish(TOPIC"kuh/light_sp", 1, false, strFVal);
//itoa(lightDB, strFVal, 10);
//mqttClient.publish(TOPIC"kuh/light_db", 1, false, strFVal);
itoa(adc, strFVal, 10);
mqttClient.publish(TOPIC"kuh/light_cur", 1, false, strFVal);
if(!isnan(tempHol)){
dtostrf(tempHol, 6, 1, strFVal);
trim(strFVal);
mqttClient.publish(TOPIC"kuh/hol_top", 1, false, strFVal);
}
if(!isnan(tempHoM)){
dtostrf(tempHoM, 6, 1, strFVal);
trim(strFVal);
mqttClient.publish(TOPIC"kuh/hol_down", 1, false, strFVal);
}
if(!isnan(tempMor)){
dtostrf(tempMor, 6, 1, strFVal);
trim(strFVal);
mqttClient.publish(TOPIC"kuh/moroz", 1, false, strFVal);
}
ultoa(crun, strFVal, 10);
mqttClient.publish(TOPIC"kuh/millis", 1, false, strFVal);
digitalWrite(BLUE, LOW);
}
void getTemp()
{
static bool readTemp = false;
if (readTemp){
sensors.setWaitForConversion(false);
sensors.requestTemperatures();
readTemp = !readTemp;
}
else{
float t = sensors.getTempC(da[nSens]);//ByIndex(nSens);
if ((t > -127) && (t < 85)){
stat[nSens] = 1;
switch(nSens){
case 0:
if (!isnan(tempOut)) tempOut += (t - tempOut) / 240.0f;
else tempOut = t;
break;
case 1:
if (!isnan(tempHol)) tempHol += (t - tempHol) * 0.05f;
else tempHol = t;
break;
case 2:
if (!isnan(tempHoM)) tempHoM += (t - tempHoM) * 0.05f;
else tempHoM = t;
break;
case 3:
if (!isnan(tempMor)) tempMor += (t - tempMor) * 0.05f;
else tempMor = t;
break;
}
}
else stat[nSens] = 0;
if (++nSens > 3){
nSens = 0;
readTemp = !readTemp;
}
}
//n++;
}
void connectToWifi() {
WiFi.begin(ssid, password);
}
void connectToMqtt() {
mqttClient.connect();
}
void onWifiConnect(const WiFiEventStationModeGotIP& event) {
connectToMqtt();
}
void onWifiDisconnect(const WiFiEventStationModeDisconnected& event) {
mqttReconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
wifiReconnectTimer.once(2, connectToWifi);
}
void onMqttConnect(bool sessionPresent) {
char v[6];
itoa(lightData.SP, v, 10);
mqttClient.publish(TOPIC"kuh/light_sp", 1, false, v);
mqttClient.publish(TOPIC"kuh/light_sp_set", 1, false, v);
itoa(lightData.DB, v, 10);
mqttClient.publish(TOPIC"kuh/light_db", 1, false, v);
mqttClient.publish(TOPIC"kuh/light_db_set", 1, false, v);
mqttClient.publish(TOPIC"kuh/move", 1, false, mv == 1 ? "1" : "0");
mqttClient.subscribe(TOPIC"kuh/light_sp_set", 1);
mqttClient.subscribe(TOPIC"kuh/light_db_set", 1);
digitalWrite(BLUE, LOW);
}
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
if (WiFi.isConnected()) {
mqttReconnectTimer.once(2, connectToMqtt);
}
digitalWrite(BLUE, HIGH);
}
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
bool w = false;
char v[6];
if(strcmp(topic, TOPIC"kuh/light_sp_set") == 0){
lightSP = atoi(payload);
w = true;
itoa(lightData.SP, v, 10);
mqttClient.publish(TOPIC"kuh/light_sp", 1, false, v);
}
if(strcmp(topic, TOPIC"kuh/light_db_set") == 0){
lightDB = atoi(payload);
w = true;
itoa(lightData.DB, v, 10);
mqttClient.publish(TOPIC"kuh/light_db", 1, false, v);
}
if(w){
lightData.SP = lightSP;
lightData.DB = lightDB;
EEPROM.put(0, lightData);
EEPROM.commit();
}
}
void trim(char *s)
{
// удаляем пробелы и табы с начала строки:
unsigned int i=0,j;
while((s[i]==' ')||(s[i]=='\t'))
{
i++;
}
if(i>0)
{
for(j=0; j < strlen(s); j++)
{
s[j]=s[j+i];
}
s[j]='\0';
}
// удаляем пробелы и табы с конца строки:
i=strlen(s)-1;
while((s[i]==' ')||(s[i]=='\t'))
{
i--;
}
if(i < (strlen(s)-1))
{
s[i+1]='\0';
}
}