225 lines
6.4 KiB
C++
225 lines
6.4 KiB
C++
//#include <PubSubClient.h>
|
|
#include <ArduinoJson.h>
|
|
#include <IPAddress.h>
|
|
#include <DallasTemperature.h>
|
|
|
|
// My Libraries
|
|
#include <secrets.h>
|
|
#include <Global.h>
|
|
#include <Communicator.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";
|
|
int tank_setpoint = 28;
|
|
|
|
WiFiClient net;
|
|
|
|
ControlDevice DEVICE_LIST[3];
|
|
int TOTAL_DEVICES = 0;
|
|
|
|
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;
|
|
|
|
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) {
|
|
for (auto kvp : src) {
|
|
dest[kvp.key()] = kvp.value();
|
|
}
|
|
}
|
|
|
|
/* Setup MQTT discovery for chiller tank control.
|
|
*
|
|
* Using climate device.
|
|
*/
|
|
void climateDevice(String name, byte ds18b20[], bool multimode=false) {
|
|
int setpoint_count = 0;
|
|
String name_slug = slugify(name);
|
|
|
|
String config_topic = "homeassistant/climate/" + name_slug + "_" + chipid + "/config";
|
|
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;
|
|
entity["uniq_id"] = chipid + "_" + name_slug;
|
|
entity["name"] = name;
|
|
entity["value_template"] = "{{ value }}";
|
|
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
|
|
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_stat_t"] = topic_root + MODE_STATE;
|
|
JsonArray modes = entity.createNestedArray("modes");
|
|
modes.add("off");
|
|
modes.add("cool");
|
|
|
|
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_stat_t"] = topic_root + TEMP_STATE;
|
|
entity["curr_temp_t"] = topic_root + TEMP_CURRENT;
|
|
entity["curr_temp_tpl"] = "{{ value }}";
|
|
device.current_temp_topic= topic_root + TEMP_CURRENT;
|
|
|
|
if (multimode == true) {
|
|
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_stat_t"] = topic_root + TEMP_HI_STATE;
|
|
|
|
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_stat_t"] = topic_root + TEMP_LO_STATE;
|
|
modes.add("heat");
|
|
modes.add("auto");
|
|
}
|
|
JsonObject dev = entity.createNestedObject("dev");
|
|
dev["name"] = DEVICE_NAME;
|
|
dev["mdl"] = DEVICE_MDL;
|
|
dev["sw"] = DEVICE_SW;
|
|
dev["mf"] = DEVICE_MF;
|
|
JsonArray ids = dev.createNestedArray("ids");
|
|
ids.add(chipid);
|
|
//dev["ids"] = "[\"" + chipid +"\"]";
|
|
|
|
DEVICE_LIST[TOTAL_DEVICES] = device;
|
|
TOTAL_DEVICES++;
|
|
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() {
|
|
hass_comm.connectCallback(&mqttCallback);
|
|
|
|
const char* ssid = WIFI_SSID;
|
|
const char* password = WIFI_PASSWORD;
|
|
sensors.begin();
|
|
sensors.setResolution(glycol_ds18b20, 9);
|
|
|
|
Serial.begin(115200);
|
|
WiFi.begin(ssid, password);
|
|
|
|
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
|
Serial.println("WiFi Failed!");
|
|
return;
|
|
}
|
|
Serial.println();
|
|
Serial.print("IP Address: ");
|
|
Serial.println(WiFi.localIP());
|
|
|
|
climateDevice("Coolant Tank", glycol_ds18b20);
|
|
climateDevice("Fermenter 1", fermA_ds18b20,true);
|
|
climateDevice("Fermenter 2", fermB_ds18b20,true);
|
|
|
|
SendUpdate();
|
|
lastMillis = millis();
|
|
}
|
|
|
|
void loop() {
|
|
currentMillis = millis();
|
|
|
|
if (currentMillis - lastMillis >= 10000) {
|
|
sensors.requestTemperatures();
|
|
SendUpdate();
|
|
lastMillis = currentMillis;
|
|
}
|
|
|
|
delay(100);
|
|
hass_comm.loop();
|
|
}
|