diff --git a/.gitignore b/.gitignore index c23d77e..ac720c6 100755 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ doc/ debug.txt *.geany *.tags +tags *.bin diff --git a/lib/Communicator/communicator.cpp b/lib/Communicator/Communicator.cpp similarity index 67% rename from lib/Communicator/communicator.cpp rename to lib/Communicator/Communicator.cpp index 6877c53..2b2fc63 100644 --- a/lib/Communicator/communicator.cpp +++ b/lib/Communicator/Communicator.cpp @@ -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->mqttCallback = cmd; + this->mqttCallback = mqttCallback; 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() { _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) { String payload; serializeJson(entity, payload); @@ -89,21 +103,34 @@ void Communicator::mqtt_discovery(const String topic, StaticJsonDocument<1536> & { 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"]); + const char* mode = entity["mode_cmd_t"]; + if (mode) { + Subscribe(mode); + } + 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(); } } - + 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); } diff --git a/lib/Communicator/Communicator.h b/lib/Communicator/Communicator.h new file mode 100644 index 0000000..12c47e2 --- /dev/null +++ b/lib/Communicator/Communicator.h @@ -0,0 +1,31 @@ +#ifndef MyClass_h +#define MyClass_h + +#include +#include +#include + +#include +#include + +#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 diff --git a/lib/Communicator/communicator.h b/lib/Communicator/communicator.h deleted file mode 100644 index de83744..0000000 --- a/lib/Communicator/communicator.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef MyClass_h -#define MyClass_h - -#include -#include -#include - -#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 diff --git a/lib/Device/Device.h b/lib/Device/Device.h index 7d65365..444e934 100644 --- a/lib/Device/Device.h +++ b/lib/Device/Device.h @@ -14,6 +14,8 @@ const char version[] = "0.0.1"; #define ACTION_TPC "action/state" #define MODE_SET "mode/set" #define MODE_STATE "mode/state" +#define SWING_STATE "swing/state" +#define SWING_SET "swing/set" #define TEMP_SET "temp/set" #define TEMP_STATE "temp/state" #define TEMP_CURRENT "temp/current" @@ -53,34 +55,68 @@ const char version[] = "0.0.1"; #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)(); -const size_t DOC_SIZE = JSON_OBJECT_SIZE(29) + JSON_ARRAY_SIZE(4); + struct CommandTopic { - ptr CmdFunc; + //~ ptr CmdFunc; + byte* Setting; String CmdTopic; }; +struct Mode { + String CmdTopic; + String StateTopic; + String Setting; +}; + +struct SetPoint { + String CmdTopic; + String StateTopic; + int Setting; +}; + struct ControlDevice { String name; // "Glycol Chiller" 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) { - for (int i=0;igetTempC(glycol_tank); + if(tempC == DEVICE_DISCONNECTED_C) + { + Serial.println("Error: Could not read temperature data"); + return 0; } - return 0; -} + Serial.print("Temp C: "); + Serial.print(tempC); + Serial.print(" Temp F: "); + return DallasTemperature::toFahrenheit(tempC); +} #endif diff --git a/lib/Device/globals.h b/lib/Device/globals.h deleted file mode 100644 index da28ee7..0000000 --- a/lib/Device/globals.h +++ /dev/null @@ -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"; diff --git a/lib/Global/Global.h b/lib/Global/Global.h index d712593..520def4 100644 --- a/lib/Global/Global.h +++ b/lib/Global/Global.h @@ -7,11 +7,14 @@ source repository. #define GLOBAL_H #define DEVICE_SW "0.0.1" -auto chipid = String(ESP.getChipId(), HEX); + #define DEVICE_NAME "Glycol Chiller" #define DEVICE_MDL "Chillenator v0.1" #define DEVICE_MF "Damn Yankee Brewing" #define FERMENTER_COUNT 2 +#define ONE_WIRE_BUS D2 + +const size_t DOC_SIZE = JSON_OBJECT_SIZE(29) + JSON_ARRAY_SIZE(4); #endif diff --git a/lib/communicator/communicator.cpp b/lib/communicator/communicator.cpp deleted file mode 100644 index dfb0bc0..0000000 --- a/lib/communicator/communicator.cpp +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/lib/communicator/communicator.h b/lib/communicator/communicator.h deleted file mode 100644 index de83744..0000000 --- a/lib/communicator/communicator.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef MyClass_h -#define MyClass_h - -#include -#include -#include - -#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 diff --git a/lib/slowPWM/slowPWM.h b/lib/slowPWM/slowPWM.h deleted file mode 100755 index 3acfeae..0000000 --- a/lib/slowPWM/slowPWM.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef SLOWPWM_h -#define SLOWPWM_h - -#include - -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 diff --git a/src/FermController/FermController.ino b/src/FermController/FermController.ino index 37d8141..e922efa 100644 --- a/src/FermController/FermController.ino +++ b/src/FermController/FermController.ino @@ -1,29 +1,73 @@ //#include #include #include +#include // My Libraries #include #include -#include +#include #include +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; -void mqttCallback(char *topic, byte *payload, unsigned int length) { - Serial.print("incoming: "); - Serial.println(topic); - for (unsigned int i = 0; i < length; i++) - { - Serial.print((char)payload[i]); - } - Serial.println(""); -} +ControlDevice DEVICE_LIST[3]; +int TOTAL_DEVICES = 0; -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 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"; + 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"; - entity["mode_stat_tpl"] = "{{ value_json }}"; + 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"; + 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["temp_stat_tpl"] = "{{ value_json }}"; - entity["curr_temp_t"] = topic_root + "temp/current"; + 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) { - 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_stat_t"] = topic_root + "temp_hi/state"; - entity["temp_hi_stat_tpl"] = "{{ value_json }}"; + entity["temp_hi_stat_t"] = topic_root + TEMP_HI_STATE; - 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_stat_t"] = topic_root + "temp_lo/state"; - entity["temp_lo_stat_tpl"] = "{{ value_json }}"; + entity["temp_lo_stat_t"] = topic_root + TEMP_LO_STATE; modes.add("heat"); modes.add("auto"); } @@ -84,12 +157,41 @@ void climateDevice(String name, boolean multimode=false) { 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= 10000) { + sensors.requestTemperatures(); + SendUpdate(); + lastMillis = currentMillis; + } + + delay(100); hass_comm.loop(); }