Lots of changes.
Closer to a working model. 2-way communication is working and devices can report temperature readings. Need to get the actual control logic done and clean this garbage up.
This commit is contained in:
parent
4619ce1d17
commit
74806fe198
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,4 +9,5 @@ doc/
|
|||||||
debug.txt
|
debug.txt
|
||||||
*.geany
|
*.geany
|
||||||
*.tags
|
*.tags
|
||||||
|
tags
|
||||||
*.bin
|
*.bin
|
||||||
|
@ -1,11 +1,20 @@
|
|||||||
#include "communicator.h"
|
#include "Communicator.h"
|
||||||
|
|
||||||
Communicator::Communicator(WiFiClient& network, void (*cmd)(char *topic, byte *payload, unsigned int length)) {
|
Communicator::Communicator(WiFiClient& network, CALLBACK_SIGNATURE) {
|
||||||
this->_net = network;
|
this->_net = network;
|
||||||
this->mqttCallback = cmd;
|
this->mqttCallback = mqttCallback;
|
||||||
this->_mqtt_client.setBufferSize(1536);
|
this->_mqtt_client.setBufferSize(1536);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Communicator::Communicator(WiFiClient& network) {
|
||||||
|
this->_net = network;
|
||||||
|
this->_mqtt_client.setBufferSize(1536);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Communicator::connectCallback(CALLBACK_SIGNATURE) {
|
||||||
|
this->mqttCallback = mqttCallback;
|
||||||
|
}
|
||||||
|
|
||||||
void Communicator::loop() {
|
void Communicator::loop() {
|
||||||
_mqtt_client.loop();
|
_mqtt_client.loop();
|
||||||
}
|
}
|
||||||
@ -80,6 +89,11 @@ bool Communicator::ConnectMQTT(const String &server, const String &name, const S
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Communicator::Subscribe(const char* topic) {
|
||||||
|
Serial.println("Subscribe to: " + String(topic));
|
||||||
|
_mqtt_client.subscribe(topic);
|
||||||
|
}
|
||||||
|
|
||||||
void Communicator::mqtt_discovery(const String topic, StaticJsonDocument<1536> &entity) {
|
void Communicator::mqtt_discovery(const String topic, StaticJsonDocument<1536> &entity) {
|
||||||
String payload;
|
String payload;
|
||||||
serializeJson(entity, payload);
|
serializeJson(entity, payload);
|
||||||
@ -89,21 +103,34 @@ void Communicator::mqtt_discovery(const String topic, StaticJsonDocument<1536> &
|
|||||||
{
|
{
|
||||||
Serial.print("Sending discovery payload to ");
|
Serial.print("Sending discovery payload to ");
|
||||||
Serial.println(topic);
|
Serial.println(topic);
|
||||||
Serial.println("");
|
|
||||||
Serial.println(payload);
|
Serial.println(payload);
|
||||||
Serial.println("");
|
|
||||||
|
|
||||||
_mqtt_client.publish(topic.c_str(), payload.c_str(), false);
|
_mqtt_client.publish(topic.c_str(), payload.c_str(), false);
|
||||||
|
|
||||||
if (entity.containsKey("mode_cmd_t")) _mqtt_client.subscribe(entity["mode_cmd_t"]);
|
const char* mode = entity["mode_cmd_t"];
|
||||||
if (entity.containsKey("temp_cmd_t")) _mqtt_client.subscribe(entity["temp_cmd_t"]);
|
if (mode) {
|
||||||
if (entity.containsKey("temp_hi_cmd_t")) _mqtt_client.subscribe(entity["temp_hi_cmd_t"]);
|
Subscribe(mode);
|
||||||
if (entity.containsKey("temp_lo_cmd_t")) _mqtt_client.subscribe(entity["temp_lo_cmd_t"]);
|
}
|
||||||
|
const char* temp = entity["temp_cmd_t"];
|
||||||
|
if (temp) {
|
||||||
|
Subscribe(temp);
|
||||||
|
}
|
||||||
|
const char* temp_hi = entity["temp_hi_cmd_t"];
|
||||||
|
if (temp_hi) {
|
||||||
|
Subscribe(temp_hi);
|
||||||
|
}
|
||||||
|
const char* temp_lo = entity["temp_lo_cmd_t"];
|
||||||
|
if (temp_lo) {
|
||||||
|
Subscribe(temp_lo);
|
||||||
|
}
|
||||||
|
|
||||||
_mqtt_client.loop();
|
_mqtt_client.loop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Communicator::publish_data(String topic, String value) {
|
void Communicator::publish_data(String topic, String value) {
|
||||||
_mqtt_client.publish(topic.c_str(), value.c_str(), false);
|
Serial.print(topic);
|
||||||
|
Serial.print(" --> ");
|
||||||
|
Serial.println(value);
|
||||||
|
_mqtt_client.publish(topic.c_str(), value.c_str(), true);
|
||||||
}
|
}
|
31
lib/Communicator/Communicator.h
Normal file
31
lib/Communicator/Communicator.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef MyClass_h
|
||||||
|
#define MyClass_h
|
||||||
|
|
||||||
|
#include <PubSubClient.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
|
||||||
|
#include <Global.h>
|
||||||
|
#include <secrets.h>
|
||||||
|
|
||||||
|
#define CALLBACK_SIGNATURE void (*mqttCallback)(char *topic, byte *payload, unsigned int length)
|
||||||
|
|
||||||
|
class Communicator {
|
||||||
|
public:
|
||||||
|
Communicator(WiFiClient&);
|
||||||
|
Communicator(WiFiClient&, CALLBACK_SIGNATURE);
|
||||||
|
|
||||||
|
CALLBACK_SIGNATURE;
|
||||||
|
void connectCallback(CALLBACK_SIGNATURE);
|
||||||
|
bool ConnectMQTT(const String&, const String&, const String&, const String&);
|
||||||
|
void mqtt_discovery(const String, StaticJsonDocument<1536>&);
|
||||||
|
void publish_data(String topic, String value);
|
||||||
|
void publish_data(String topic, int value);
|
||||||
|
void Subscribe(const char* topic);
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
PubSubClient _mqtt_client;
|
||||||
|
WiFiClient _net;
|
||||||
|
};
|
||||||
|
#endif
|
@ -1,25 +0,0 @@
|
|||||||
#ifndef MyClass_h
|
|
||||||
#define MyClass_h
|
|
||||||
|
|
||||||
#include <PubSubClient.h>
|
|
||||||
#include <ArduinoJson.h>
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
|
|
||||||
#include "secrets.h"
|
|
||||||
|
|
||||||
|
|
||||||
class Communicator {
|
|
||||||
public:
|
|
||||||
Communicator(WiFiClient&, void (*mqttCallback)(char*, byte*, unsigned int));
|
|
||||||
|
|
||||||
void (*mqttCallback)(char*, byte*, unsigned int);
|
|
||||||
bool ConnectMQTT(const String&, const String&, const String&, const String&);
|
|
||||||
void mqtt_discovery(const String, StaticJsonDocument<1536>&);
|
|
||||||
void publish_data(String, String);
|
|
||||||
|
|
||||||
void loop();
|
|
||||||
private:
|
|
||||||
PubSubClient _mqtt_client;
|
|
||||||
WiFiClient _net;
|
|
||||||
};
|
|
||||||
#endif
|
|
@ -14,6 +14,8 @@ const char version[] = "0.0.1";
|
|||||||
#define ACTION_TPC "action/state"
|
#define ACTION_TPC "action/state"
|
||||||
#define MODE_SET "mode/set"
|
#define MODE_SET "mode/set"
|
||||||
#define MODE_STATE "mode/state"
|
#define MODE_STATE "mode/state"
|
||||||
|
#define SWING_STATE "swing/state"
|
||||||
|
#define SWING_SET "swing/set"
|
||||||
#define TEMP_SET "temp/set"
|
#define TEMP_SET "temp/set"
|
||||||
#define TEMP_STATE "temp/state"
|
#define TEMP_STATE "temp/state"
|
||||||
#define TEMP_CURRENT "temp/current"
|
#define TEMP_CURRENT "temp/current"
|
||||||
@ -53,34 +55,68 @@ const char version[] = "0.0.1";
|
|||||||
|
|
||||||
#define TOPIC_LIMIT 4
|
#define TOPIC_LIMIT 4
|
||||||
|
|
||||||
typedef void (*ptr)(uint8_t*);
|
#define OFF 0
|
||||||
|
#define COOL 1
|
||||||
|
#define HEAT 2
|
||||||
|
#define AUTO 3
|
||||||
|
|
||||||
|
uint8_t CHILLER_SP = 70;
|
||||||
|
uint8_t FERMA_SP = 70;
|
||||||
|
uint8_t FERMB_SP = 70;
|
||||||
|
|
||||||
|
uint8_t CHILLER_MD = OFF;
|
||||||
|
uint8_t FERMA_MD = OFF;
|
||||||
|
uint8_t FERMB_MD = OFF;
|
||||||
|
|
||||||
|
//~ typedef void (*ptr)(uint8_t*, uint8_t*);
|
||||||
//typedef ptr (*pm)();
|
//typedef ptr (*pm)();
|
||||||
|
|
||||||
const size_t DOC_SIZE = JSON_OBJECT_SIZE(29) + JSON_ARRAY_SIZE(4);
|
|
||||||
|
|
||||||
struct CommandTopic {
|
struct CommandTopic {
|
||||||
ptr CmdFunc;
|
//~ ptr CmdFunc;
|
||||||
|
byte* Setting;
|
||||||
String CmdTopic;
|
String CmdTopic;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Mode {
|
||||||
|
String CmdTopic;
|
||||||
|
String StateTopic;
|
||||||
|
String Setting;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SetPoint {
|
||||||
|
String CmdTopic;
|
||||||
|
String StateTopic;
|
||||||
|
int Setting;
|
||||||
|
};
|
||||||
|
|
||||||
struct ControlDevice {
|
struct ControlDevice {
|
||||||
String name; // "Glycol Chiller"
|
String name; // "Glycol Chiller"
|
||||||
String topic_root; // "brewhouse/"
|
String topic_root; // "brewhouse/"
|
||||||
CommandTopic command_topics[TOPIC_LIMIT];
|
String current_temp_topic;
|
||||||
|
byte temp_sensor[8];
|
||||||
|
String action_topic;
|
||||||
|
String action_state;
|
||||||
|
String swing_topic;
|
||||||
|
String swing_state;
|
||||||
|
Mode mode;
|
||||||
|
SetPoint setpoints[3];
|
||||||
|
bool dual;
|
||||||
};
|
};
|
||||||
|
|
||||||
ptr CmdLookup(String lookup_topic, ControlDevice devices[], int device_count) {
|
float UpdateTemperature(DallasTemperature *sensors, DeviceAddress glycol_tank) {
|
||||||
for (int i=0;i<device_count;i++) {
|
// method 2 - faster
|
||||||
ControlDevice this_device = devices[i];
|
float tempC = sensors->getTempC(glycol_tank);
|
||||||
for (int j=0;j<TOPIC_LIMIT;j++) {
|
if(tempC == DEVICE_DISCONNECTED_C)
|
||||||
CommandTopic this_topic = this_device.command_topics[j];
|
{
|
||||||
String topic = this_topic.CmdTopic;
|
Serial.println("Error: Could not read temperature data");
|
||||||
if (topic == lookup_topic) {
|
return 0;
|
||||||
return this_topic.CmdFunc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
Serial.print("Temp C: ");
|
||||||
}
|
Serial.print(tempC);
|
||||||
|
Serial.print(" Temp F: ");
|
||||||
|
return DallasTemperature::toFahrenheit(tempC);
|
||||||
|
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
TOPIC_ROOT + suffix;
|
|
||||||
TOPIC_ROOT + suffix;
|
|
||||||
TOPIC_ROOT + "mode/set";
|
|
||||||
TOPIC_ROOT + "mode/state";
|
|
||||||
TOPIC_ROOT + "temp/set";
|
|
||||||
TOPIC_ROOT + "temp/state";
|
|
||||||
TOPIC_ROOT + "temp/current";
|
|
||||||
TOPIC_ROOT + "temp_hi/set";
|
|
||||||
TOPIC_ROOT + "temp_hi/state";
|
|
||||||
TOPIC_ROOT + "temp_lo/set";
|
|
||||||
TOPIC_ROOT + "temp_lo/state";
|
|
@ -7,11 +7,14 @@ source repository.
|
|||||||
#define GLOBAL_H
|
#define GLOBAL_H
|
||||||
|
|
||||||
#define DEVICE_SW "0.0.1"
|
#define DEVICE_SW "0.0.1"
|
||||||
auto chipid = String(ESP.getChipId(), HEX);
|
|
||||||
|
|
||||||
#define DEVICE_NAME "Glycol Chiller"
|
#define DEVICE_NAME "Glycol Chiller"
|
||||||
#define DEVICE_MDL "Chillenator v0.1"
|
#define DEVICE_MDL "Chillenator v0.1"
|
||||||
#define DEVICE_MF "Damn Yankee Brewing"
|
#define DEVICE_MF "Damn Yankee Brewing"
|
||||||
#define FERMENTER_COUNT 2
|
#define FERMENTER_COUNT 2
|
||||||
|
#define ONE_WIRE_BUS D2
|
||||||
|
|
||||||
|
const size_t DOC_SIZE = JSON_OBJECT_SIZE(29) + JSON_ARRAY_SIZE(4);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,109 +0,0 @@
|
|||||||
#include "communicator.h"
|
|
||||||
|
|
||||||
Communicator::Communicator(WiFiClient& network, void (*cmd)(char *topic, byte *payload, unsigned int length)) {
|
|
||||||
this->_net = network;
|
|
||||||
this->mqttCallback = cmd;
|
|
||||||
this->_mqtt_client.setBufferSize(1536);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Communicator::loop() {
|
|
||||||
_mqtt_client.loop();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Communicator::ConnectMQTT(const String &server, const String &name, const String &user, const String &password) {
|
|
||||||
_mqtt_client.setClient(_net);
|
|
||||||
_mqtt_client.setServer(server.c_str(), 1883);
|
|
||||||
_mqtt_client.setCallback(mqttCallback);
|
|
||||||
|
|
||||||
byte i = 0;
|
|
||||||
|
|
||||||
if (_mqtt_client.connected()) return true;
|
|
||||||
|
|
||||||
while (!_mqtt_client.connected() && (i < 3)) {
|
|
||||||
Serial.println("Attempt MQTT Connection.");
|
|
||||||
boolean ret;
|
|
||||||
ret = _mqtt_client.connect(name.c_str(), user.c_str(), password.c_str());
|
|
||||||
if (ret) {
|
|
||||||
Serial.println("Connected to MQTT");
|
|
||||||
return true;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
int Status = _mqtt_client.state();
|
|
||||||
|
|
||||||
switch (Status)
|
|
||||||
{
|
|
||||||
case -4:
|
|
||||||
Serial.println(F("Connection timeout"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case -3:
|
|
||||||
Serial.println(F("Connection lost"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case -2:
|
|
||||||
Serial.println(F("Connect failed"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case -1:
|
|
||||||
Serial.println(F("Disconnected"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
Serial.println(F("Bad protocol"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
Serial.println(F("Bad client ID"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
Serial.println(F("Unavailable"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
Serial.println(F("Bad credentials"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5:
|
|
||||||
Serial.println(F("Unauthorized"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Serial.print(".");
|
|
||||||
i++;
|
|
||||||
delay(5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Communicator::mqtt_discovery(const String topic, StaticJsonDocument<1536> &entity) {
|
|
||||||
String payload;
|
|
||||||
serializeJson(entity, payload);
|
|
||||||
|
|
||||||
bool response = ConnectMQTT(MQTT_BROKER.toString(), MQTT_NAME, MQTT_USER, MQTT_PASSWORD);
|
|
||||||
if (response)
|
|
||||||
{
|
|
||||||
Serial.print("Sending discovery payload to ");
|
|
||||||
Serial.println(topic);
|
|
||||||
Serial.println("");
|
|
||||||
Serial.println(payload);
|
|
||||||
Serial.println("");
|
|
||||||
|
|
||||||
_mqtt_client.publish(topic.c_str(), payload.c_str(), false);
|
|
||||||
|
|
||||||
if (entity.containsKey("mode_cmd_t")) _mqtt_client.subscribe(entity["mode_cmd_t"]);
|
|
||||||
if (entity.containsKey("temp_cmd_t")) _mqtt_client.subscribe(entity["temp_cmd_t"]);
|
|
||||||
if (entity.containsKey("temp_hi_cmd_t")) _mqtt_client.subscribe(entity["temp_hi_cmd_t"]);
|
|
||||||
if (entity.containsKey("temp_lo_cmd_t")) _mqtt_client.subscribe(entity["temp_lo_cmd_t"]);
|
|
||||||
|
|
||||||
_mqtt_client.loop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Communicator::publish_data(String topic, String value) {
|
|
||||||
_mqtt_client.publish(topic.c_str(), value.c_str(), false);
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
#ifndef MyClass_h
|
|
||||||
#define MyClass_h
|
|
||||||
|
|
||||||
#include <PubSubClient.h>
|
|
||||||
#include <ArduinoJson.h>
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
|
|
||||||
#include "secrets.h"
|
|
||||||
|
|
||||||
|
|
||||||
class Communicator {
|
|
||||||
public:
|
|
||||||
Communicator(WiFiClient&, void (*mqttCallback)(char*, byte*, unsigned int));
|
|
||||||
|
|
||||||
void (*mqttCallback)(char*, byte*, unsigned int);
|
|
||||||
bool ConnectMQTT(const String&, const String&, const String&, const String&);
|
|
||||||
void mqtt_discovery(const String, StaticJsonDocument<1536>&);
|
|
||||||
void publish_data(String, String);
|
|
||||||
|
|
||||||
void loop();
|
|
||||||
private:
|
|
||||||
PubSubClient _mqtt_client;
|
|
||||||
WiFiClient _net;
|
|
||||||
};
|
|
||||||
#endif
|
|
@ -1,42 +0,0 @@
|
|||||||
#ifndef SLOWPWM_h
|
|
||||||
#define SLOWPWM_h
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
class slowPWM {
|
|
||||||
private:
|
|
||||||
byte outputPin;
|
|
||||||
unsigned long period;
|
|
||||||
unsigned long lastSwitchTime;
|
|
||||||
byte outputState;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void begin(byte pin, unsigned long per) {
|
|
||||||
outputPin = pin;
|
|
||||||
period = per;
|
|
||||||
lastSwitchTime = 0;
|
|
||||||
outputState = LOW;
|
|
||||||
pinMode(pin, OUTPUT);
|
|
||||||
Serial.println("Setup PWM");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte compute(byte duty) {
|
|
||||||
unsigned long onTime = (duty * period) / 100;
|
|
||||||
unsigned long offTime = period - onTime;
|
|
||||||
unsigned long currentTime = millis();
|
|
||||||
|
|
||||||
if (duty == 0) {
|
|
||||||
outputState = LOW;
|
|
||||||
} else if (outputState == HIGH && (currentTime - lastSwitchTime >= onTime)) {
|
|
||||||
lastSwitchTime = currentTime;
|
|
||||||
outputState = LOW;
|
|
||||||
|
|
||||||
} else if (outputState == LOW && (currentTime - lastSwitchTime >= offTime)) {
|
|
||||||
lastSwitchTime = currentTime;
|
|
||||||
outputState = HIGH;
|
|
||||||
}
|
|
||||||
|
|
||||||
return outputState;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
@ -1,29 +1,73 @@
|
|||||||
//#include <PubSubClient.h>
|
//#include <PubSubClient.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <IPAddress.h>
|
#include <IPAddress.h>
|
||||||
|
#include <DallasTemperature.h>
|
||||||
|
|
||||||
// My Libraries
|
// My Libraries
|
||||||
#include <secrets.h>
|
#include <secrets.h>
|
||||||
#include <Global.h>
|
#include <Global.h>
|
||||||
#include <communicator.h>
|
#include <Communicator.h>
|
||||||
#include <Device.h>
|
#include <Device.h>
|
||||||
|
|
||||||
|
OneWire oneWire(ONE_WIRE_BUS);
|
||||||
|
DallasTemperature sensors(&oneWire);
|
||||||
|
byte glycol_ds18b20[8] = {0x28,0xFF,0x64,0x0E,0x7F,0x57,0x09,0x66};
|
||||||
|
byte fermA_ds18b20[8] = {0x28,0xFF,0x64,0x0E,0x7F,0x57,0x09,0x66};
|
||||||
|
byte fermB_ds18b20[8] = {0x28,0xFF,0x64,0x0E,0x7F,0x57,0x09,0x66};
|
||||||
|
|
||||||
String chiller_state = "idle";
|
String chiller_state = "idle";
|
||||||
int tank_setpoint = 28;
|
int tank_setpoint = 28;
|
||||||
|
|
||||||
WiFiClient net;
|
WiFiClient net;
|
||||||
|
|
||||||
void mqttCallback(char *topic, byte *payload, unsigned int length) {
|
ControlDevice DEVICE_LIST[3];
|
||||||
Serial.print("incoming: ");
|
int TOTAL_DEVICES = 0;
|
||||||
Serial.println(topic);
|
|
||||||
for (unsigned int i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
Serial.print((char)payload[i]);
|
|
||||||
}
|
|
||||||
Serial.println("");
|
|
||||||
}
|
|
||||||
|
|
||||||
Communicator hass_comm = Communicator(net, &mqttCallback);
|
auto chipid = String(ESP.getChipId(), HEX);
|
||||||
|
|
||||||
|
Communicator hass_comm = Communicator(net);
|
||||||
|
|
||||||
|
unsigned long lastMillis;
|
||||||
|
unsigned long currentMillis;
|
||||||
|
|
||||||
|
void mqttCallback(char *topic, byte *payload, unsigned int length) {
|
||||||
|
payload[length] = '\0';
|
||||||
|
|
||||||
|
for (int i=0;i<TOTAL_DEVICES;i++) {
|
||||||
|
if (strcmp((char *)topic, (DEVICE_LIST[i].mode.CmdTopic).c_str() ) == 0){
|
||||||
|
DEVICE_LIST[i].mode.Setting = (char*)payload;
|
||||||
|
Serial.print("Swing: ");
|
||||||
|
Serial.println(DEVICE_LIST[i].swing_topic);
|
||||||
|
if (DEVICE_LIST[i].mode.Setting == "auto") {
|
||||||
|
DEVICE_LIST[i].swing_state = "off";
|
||||||
|
hass_comm.publish_data(DEVICE_LIST[i].swing_topic, "on");
|
||||||
|
} else {
|
||||||
|
DEVICE_LIST[i].swing_state = "on";
|
||||||
|
hass_comm.publish_data(DEVICE_LIST[i].swing_topic, "off");
|
||||||
|
}
|
||||||
|
|
||||||
|
hass_comm.publish_data(DEVICE_LIST[i].mode.StateTopic, DEVICE_LIST[i].mode.Setting);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int setpoint_count;
|
||||||
|
bool dual_mode = DEVICE_LIST[i].dual;
|
||||||
|
if (dual_mode) {
|
||||||
|
setpoint_count = 3;
|
||||||
|
} else {
|
||||||
|
setpoint_count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j=0;j<setpoint_count;j++) {
|
||||||
|
String thistopic = DEVICE_LIST[i].setpoints[j].CmdTopic;
|
||||||
|
if (strcmp((char *)topic, thistopic.c_str()) == 0){
|
||||||
|
DEVICE_LIST[i].setpoints[j].Setting = atoi((char *)payload);
|
||||||
|
hass_comm.publish_data(DEVICE_LIST[i].setpoints[j].StateTopic, String(DEVICE_LIST[i].setpoints[j].Setting));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void merge(JsonObject dest, JsonObjectConst src) {
|
void merge(JsonObject dest, JsonObjectConst src) {
|
||||||
for (auto kvp : src) {
|
for (auto kvp : src) {
|
||||||
@ -35,43 +79,72 @@ void merge(JsonObject dest, JsonObjectConst src) {
|
|||||||
*
|
*
|
||||||
* Using climate device.
|
* Using climate device.
|
||||||
*/
|
*/
|
||||||
void climateDevice(String name, boolean multimode=false) {
|
void climateDevice(String name, byte ds18b20[], bool multimode=false) {
|
||||||
|
int setpoint_count = 0;
|
||||||
String name_slug = slugify(name);
|
String name_slug = slugify(name);
|
||||||
|
|
||||||
String config_topic = "homeassistant/climate/" + name_slug + "_" + chipid + "/config";
|
String config_topic = "homeassistant/climate/" + name_slug + "_" + chipid + "/config";
|
||||||
String topic_root = "brewhouse/" + name_slug + "/";
|
String topic_root = "brewhouse/" + name_slug + "/";
|
||||||
|
|
||||||
|
ControlDevice device;
|
||||||
|
device.dual = false;
|
||||||
|
device.name = name;
|
||||||
|
device.topic_root = topic_root;
|
||||||
|
|
||||||
|
for (int i=0;i<8;i++) {
|
||||||
|
device.temp_sensor[i] = ds18b20[i];
|
||||||
|
}
|
||||||
|
|
||||||
StaticJsonDocument<1536> entity;
|
StaticJsonDocument<1536> entity;
|
||||||
entity["uniq_id"] = chipid + "_" + name_slug;
|
entity["uniq_id"] = chipid + "_" + name_slug;
|
||||||
entity["name"] = name;
|
entity["name"] = name;
|
||||||
|
entity["value_template"] = "{{ value }}";
|
||||||
entity["temp_unit"] = "F";
|
entity["temp_unit"] = "F";
|
||||||
|
entity["max_temp"] = 100;
|
||||||
|
entity["min_temp"] = 0;
|
||||||
|
entity["swing_mode_stat_t"] = topic_root + SWING_STATE;
|
||||||
|
device.swing_topic = topic_root + SWING_STATE;
|
||||||
|
|
||||||
|
entity["act_t"] = topic_root + ACTION_TPC;
|
||||||
|
entity["act_tpl"] = "{{ value }}";
|
||||||
|
device.action_topic = topic_root + ACTION_TPC;
|
||||||
|
|
||||||
// Mode setup
|
// Mode setup
|
||||||
entity["mode_cmd_t"] = topic_root + "mode/set";
|
entity["mode_cmd_t"] = topic_root + MODE_SET;
|
||||||
|
Mode mode = {topic_root + MODE_SET, topic_root + MODE_STATE, "off"};
|
||||||
|
device.mode = mode;
|
||||||
|
|
||||||
entity["mode_cmd_tpl"] = "{{ value }}";
|
entity["mode_cmd_tpl"] = "{{ value }}";
|
||||||
entity["mode_stat_t"] = topic_root + "mode/state";
|
entity["mode_stat_t"] = topic_root + MODE_STATE;
|
||||||
entity["mode_stat_tpl"] = "{{ value_json }}";
|
|
||||||
JsonArray modes = entity.createNestedArray("modes");
|
JsonArray modes = entity.createNestedArray("modes");
|
||||||
modes.add("off");
|
modes.add("off");
|
||||||
modes.add("cool");
|
modes.add("cool");
|
||||||
|
|
||||||
entity["temp_cmd_t"] = topic_root + "temp/set";
|
entity["temp_cmd_t"] = topic_root + TEMP_SET;
|
||||||
|
SetPoint temp = {topic_root + TEMP_SET,topic_root + TEMP_STATE,70};
|
||||||
|
device.setpoints[setpoint_count] = temp;
|
||||||
|
setpoint_count++;
|
||||||
entity["temp_cmd_tpl"] = "{{ value }}";
|
entity["temp_cmd_tpl"] = "{{ value }}";
|
||||||
entity["temp_stat_t"] = topic_root + "temp/state";
|
entity["temp_stat_t"] = topic_root + TEMP_STATE;
|
||||||
entity["temp_stat_tpl"] = "{{ value_json }}";
|
entity["curr_temp_t"] = topic_root + TEMP_CURRENT;
|
||||||
entity["curr_temp_t"] = topic_root + "temp/current";
|
|
||||||
entity["curr_temp_tpl"] = "{{ value }}";
|
entity["curr_temp_tpl"] = "{{ value }}";
|
||||||
|
device.current_temp_topic= topic_root + TEMP_CURRENT;
|
||||||
|
|
||||||
if (multimode == true) {
|
if (multimode == true) {
|
||||||
entity["temp_hi_cmd_t"] = topic_root + "temp_hi/set";
|
device.dual = true;
|
||||||
|
entity["temp_hi_cmd_t"] = topic_root + TEMP_HI_SET;
|
||||||
|
SetPoint temp_hi = {topic_root + TEMP_HI_SET, topic_root + TEMP_HI_STATE, 70};
|
||||||
|
device.setpoints[setpoint_count] = temp_hi;
|
||||||
|
setpoint_count++;
|
||||||
entity["temp_hi_cmd_tpl"] = "{{ value }}";
|
entity["temp_hi_cmd_tpl"] = "{{ value }}";
|
||||||
entity["temp_hi_stat_t"] = topic_root + "temp_hi/state";
|
entity["temp_hi_stat_t"] = topic_root + TEMP_HI_STATE;
|
||||||
entity["temp_hi_stat_tpl"] = "{{ value_json }}";
|
|
||||||
|
|
||||||
entity["temp_lo_cmd_t"] = topic_root + "temp_lo/set";
|
entity["temp_lo_cmd_t"] = topic_root + TEMP_LO_SET;
|
||||||
|
SetPoint temp_lo = {topic_root + TEMP_LO_SET, topic_root + TEMP_LO_STATE, 70};
|
||||||
|
device.setpoints[setpoint_count] = temp_lo;
|
||||||
|
setpoint_count++;
|
||||||
entity["temp_lo_cmd_tpl"] = "{{ value }}";
|
entity["temp_lo_cmd_tpl"] = "{{ value }}";
|
||||||
entity["temp_lo_stat_t"] = topic_root + "temp_lo/state";
|
entity["temp_lo_stat_t"] = topic_root + TEMP_LO_STATE;
|
||||||
entity["temp_lo_stat_tpl"] = "{{ value_json }}";
|
|
||||||
modes.add("heat");
|
modes.add("heat");
|
||||||
modes.add("auto");
|
modes.add("auto");
|
||||||
}
|
}
|
||||||
@ -84,12 +157,41 @@ void climateDevice(String name, boolean multimode=false) {
|
|||||||
ids.add(chipid);
|
ids.add(chipid);
|
||||||
//dev["ids"] = "[\"" + chipid +"\"]";
|
//dev["ids"] = "[\"" + chipid +"\"]";
|
||||||
|
|
||||||
|
DEVICE_LIST[TOTAL_DEVICES] = device;
|
||||||
|
TOTAL_DEVICES++;
|
||||||
hass_comm.mqtt_discovery(config_topic, entity);
|
hass_comm.mqtt_discovery(config_topic, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SendUpdate() {
|
||||||
|
int setpoint_count = 0;
|
||||||
|
float device_temp;
|
||||||
|
for (int i=0;i<TOTAL_DEVICES;i++) {
|
||||||
|
device_temp = UpdateTemperature(&sensors, DEVICE_LIST[i].temp_sensor);
|
||||||
|
hass_comm.publish_data(DEVICE_LIST[i].current_temp_topic, String(device_temp));
|
||||||
|
hass_comm.publish_data(DEVICE_LIST[i].mode.StateTopic, DEVICE_LIST[i].mode.Setting);
|
||||||
|
hass_comm.publish_data(DEVICE_LIST[i].action_topic, ACTION_COOLING);
|
||||||
|
bool dual_mode = DEVICE_LIST[i].dual;
|
||||||
|
|
||||||
|
if (dual_mode) {
|
||||||
|
setpoint_count = 3;
|
||||||
|
} else {
|
||||||
|
setpoint_count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j=0;j<setpoint_count;j++) {
|
||||||
|
hass_comm.publish_data(DEVICE_LIST[i].setpoints[j].StateTopic, String(DEVICE_LIST[i].setpoints[j].Setting));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
|
hass_comm.connectCallback(&mqttCallback);
|
||||||
|
|
||||||
const char* ssid = WIFI_SSID;
|
const char* ssid = WIFI_SSID;
|
||||||
const char* password = WIFI_PASSWORD;
|
const char* password = WIFI_PASSWORD;
|
||||||
|
sensors.begin();
|
||||||
|
sensors.setResolution(glycol_ds18b20, 9);
|
||||||
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
WiFi.begin(ssid, password);
|
WiFi.begin(ssid, password);
|
||||||
|
|
||||||
@ -101,20 +203,23 @@ void setup() {
|
|||||||
Serial.print("IP Address: ");
|
Serial.print("IP Address: ");
|
||||||
Serial.println(WiFi.localIP());
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
climateDevice("Coolant Tank");
|
climateDevice("Coolant Tank", glycol_ds18b20);
|
||||||
|
climateDevice("Fermenter 1", fermA_ds18b20,true);
|
||||||
|
climateDevice("Fermenter 2", fermB_ds18b20,true);
|
||||||
|
|
||||||
String f_name = "Fermenter ";
|
SendUpdate();
|
||||||
for (int i=0;i<FERMENTER_COUNT;i++) {
|
lastMillis = millis();
|
||||||
int f_num = i+1;
|
|
||||||
|
|
||||||
Serial.println(f_name + f_num);
|
|
||||||
climateDevice(f_name + f_num, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
delay(5000);
|
currentMillis = millis();
|
||||||
hass_comm.publish_data("brewhouse/coolant_tank/temp/current", String(tank_setpoint));
|
|
||||||
hass_comm.publish_data("brewhouse/coolant_tank/mode/state", chiller_state);
|
if (currentMillis - lastMillis >= 10000) {
|
||||||
|
sensors.requestTemperatures();
|
||||||
|
SendUpdate();
|
||||||
|
lastMillis = currentMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(100);
|
||||||
hass_comm.loop();
|
hass_comm.loop();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user