Well it compiles.
This commit is contained in:
parent
0a7fa301ed
commit
4619ce1d17
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,5 @@
|
||||
.DS_Store
|
||||
bin/*/
|
||||
bin/*
|
||||
*build-*
|
||||
*build*
|
||||
*~
|
||||
|
@ -73,4 +73,4 @@ $(TARGET_DIR)/$(BIN): $(SRC) $(HDRS)
|
||||
|
||||
$(BIN_DIR)/$(BIN): $(TARGET_DIR)/$(BIN)
|
||||
@ echo "$(BIN) $(BIN_DIR)/"
|
||||
@ mv $(TARGET_DIR)/$(BIN) $(BIN_DIR)/
|
||||
@ cp $(TARGET_DIR)/$(BIN) $(BIN_DIR)/
|
||||
|
Binary file not shown.
@ -1,358 +0,0 @@
|
||||
|
||||
#include "Device.h"
|
||||
|
||||
Device::Device(const uint8_t _pin_cool, const uint8_t _pin_heat, const uint8_t _pin_wire) {
|
||||
this->_pin_cool = _pin_cool;
|
||||
this->_pin_heat = _pin_heat;
|
||||
this->_pin_wire = _pin_wire;
|
||||
}
|
||||
|
||||
void Device::CoolSet(bool set_state) {
|
||||
// Set pin state
|
||||
if (set_state) {
|
||||
Serial.println("Starting cooling.");
|
||||
strcpy(_curr_action, ACTION_COOLING);
|
||||
SendState(ACTION_TPC, _curr_action);
|
||||
digitalWrite(_pin_heat, LOW); // Just to be sure.
|
||||
digitalWrite(_pin_cool, HIGH);
|
||||
} else {
|
||||
Serial.println("Stopping cooling.");
|
||||
strcpy(_curr_action, ACTION_IDLE);
|
||||
SendState(ACTION_TPC, _curr_action);
|
||||
digitalWrite(_pin_cool, LOW);
|
||||
digitalWrite(_pin_heat, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void Device::HeatSet(bool set_state) {
|
||||
if (set_state) {
|
||||
Serial.println("Starting heat.");
|
||||
strcpy(_curr_action, ACTION_HEATING);
|
||||
SendState(ACTION_TPC, _curr_action);
|
||||
digitalWrite(_pin_cool, LOW); // Just to be sure.
|
||||
digitalWrite(_pin_heat, HIGH);
|
||||
} else {
|
||||
Serial.println("Stopping heat.");
|
||||
strcpy(_curr_action, ACTION_IDLE);
|
||||
SendState(ACTION_TPC, _curr_action);
|
||||
digitalWrite(_pin_cool, LOW);
|
||||
digitalWrite(_pin_heat, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void Device::Hyst(float new_value){
|
||||
_hyst = new_value;
|
||||
}
|
||||
|
||||
float Device::Hyst(){
|
||||
return _hyst;
|
||||
}
|
||||
|
||||
void Device::Update(){
|
||||
float currentMillis = millis();
|
||||
|
||||
//Read temp sensor.
|
||||
if (currentMillis - _lastSensor >= _sensor_period) {
|
||||
//Read temperature from DS18b20
|
||||
float tempC = _sensors.getTempC(_ds_serial);
|
||||
if (tempC == DEVICE_DISCONNECTED_C) {
|
||||
Serial.println("Error: Could not read temperature data");
|
||||
} else {
|
||||
_curr_temp = DallasTemperature::toFahrenheit(tempC);
|
||||
}
|
||||
}
|
||||
|
||||
// Some helpful variables.
|
||||
bool heating = _curr_action==ACTION_HEATING;
|
||||
bool cooling = _curr_action==ACTION_COOLING;
|
||||
bool running = (heating || cooling);
|
||||
|
||||
// Adjust cool/heat on or off
|
||||
if (_mode == "cool"){
|
||||
if (_curr_temp > _temp + _hyst && !cooling) {
|
||||
CoolSet(true);
|
||||
} else if (_curr_temp <= _temp && cooling) {
|
||||
CoolSet(false);
|
||||
}
|
||||
} else if (_mode == "heat"){
|
||||
if (_curr_temp < _temp - _hyst && !heating) {
|
||||
HeatSet(true);
|
||||
} else if (_curr_temp >= _temp && heating) {
|
||||
HeatSet(false);
|
||||
}
|
||||
} else if (_mode == "auto"){
|
||||
if ((_curr_temp < _temp_lo - _hyst) && !heating) {
|
||||
HeatSet(true);
|
||||
} else if ((_curr_temp > _temp_hi + _hyst) && !cooling) {
|
||||
CoolSet(true);
|
||||
} else if (running && (_curr_temp >= _temp_lo) && (_curr_temp <= _temp_hi)) {
|
||||
if (heating) HeatSet(false);
|
||||
if (cooling) CoolSet(false);
|
||||
}
|
||||
} else {
|
||||
// IS OFF
|
||||
if (heating) HeatSet(false);
|
||||
if (cooling) CoolSet(false);
|
||||
}
|
||||
|
||||
//Send Data to broker
|
||||
if (currentMillis - _lastSend >= _send_period) {
|
||||
// Time's up, send data
|
||||
char temp[7];
|
||||
dtostrf(_curr_temp, 6, 2, temp);
|
||||
SendState(TEMP_CURRENT, temp);
|
||||
_lastSend = currentMillis;
|
||||
}
|
||||
|
||||
_mqtt_client.loop();
|
||||
}
|
||||
|
||||
void Device::AttachNet(WiFiClient &network) {
|
||||
this->_net = network;
|
||||
this->_mqtt_client.setClient(_net);
|
||||
this->_mqtt_client.setBufferSize(DOC_SIZE);
|
||||
}
|
||||
|
||||
void Device::AttachSensor(DallasTemperature &sensors, uint8_t serial[8]){
|
||||
_sensors = sensors;
|
||||
_ds_serial = serial;
|
||||
}
|
||||
|
||||
//void Device::topicRoot(const String &root) { _device_prefix = root; }
|
||||
//byte* Device::topicRoot() { return _device_prefix; }
|
||||
|
||||
void Device::SendConfig(char* broker, char* name, String &chipid, bool multimode) {
|
||||
String name_slug = slugify(name);
|
||||
String CMD_TPL = "{{ value }}";
|
||||
String STAT_TPL = "{{ value_json }}";
|
||||
|
||||
_topic_root = ROOT + name_slug;
|
||||
|
||||
String _config_topic = CONFIG_ROOT + name_slug + "_" + chipid + "/config";
|
||||
|
||||
StaticJsonDocument<DOC_SIZE> payload_doc;
|
||||
payload_doc["uniq_id"] = chipid + "_" + name_slug;
|
||||
payload_doc["name"] = name;
|
||||
payload_doc["temp_unit"] = "F";
|
||||
payload_doc["max_temp"] = _max_temp;
|
||||
payload_doc["min_temp"] = _min_temp;
|
||||
payload_doc["initial"] = _init_temp;
|
||||
|
||||
// Action Topic
|
||||
payload_doc["action_topic"] = _topic_root + ACTION_TPC;
|
||||
payload_doc["action_template"] = STAT_TPL;
|
||||
|
||||
// Mode setup
|
||||
payload_doc["mode_cmd_t"] = _topic_root + MODE_SET;
|
||||
payload_doc["mode_cmd_tpl"] = CMD_TPL;
|
||||
payload_doc["mode_stat_t"] = _topic_root + MODE_STATE;
|
||||
payload_doc["mode_stat_tpl"] = STAT_TPL;
|
||||
|
||||
JsonArray modes = payload_doc.createNestedArray("modes");
|
||||
modes.add("off");
|
||||
modes.add("cool");
|
||||
|
||||
payload_doc["temp_cmd_t"] = _topic_root + TEMP_SET;
|
||||
payload_doc["temp_cmd_tpl"] = CMD_TPL;
|
||||
payload_doc["temp_stat_t"] = _topic_root + TEMP_STATE;
|
||||
payload_doc["temp_stat_tpl"] = STAT_TPL;
|
||||
|
||||
payload_doc["curr_temp_t"] = _topic_root + TEMP_CURRENT;
|
||||
payload_doc["curr_temp_tpl"] = CMD_TPL;
|
||||
|
||||
if (multimode) {
|
||||
payload_doc["temp_hi_cmd_t"] = _topic_root + TEMP_HI_SET;
|
||||
payload_doc["temp_hi_cmd_tpl"] = CMD_TPL;
|
||||
payload_doc["temp_hi_stat_t"] = _topic_root + TEMP_HI_STATE;
|
||||
payload_doc["temp_hi_stat_tpl"] = STAT_TPL;
|
||||
|
||||
payload_doc["temp_lo_cmd_t"] = _topic_root + TEMP_LO_SET;
|
||||
payload_doc["temp_lo_cmd_tpl"] = CMD_TPL;
|
||||
payload_doc["temp_lo_stat_t"] = _topic_root + TEMP_LO_STATE;
|
||||
payload_doc["temp_lo_stat_tpl"] = STAT_TPL;
|
||||
|
||||
modes.add("heat");
|
||||
modes.add("auto");
|
||||
}
|
||||
|
||||
// Attach Device
|
||||
JsonObject dev = payload_doc.createNestedObject("dev");
|
||||
dev["name"] = DEVICE_NAME;
|
||||
dev["mdl"] = DEVICE_MDL;
|
||||
dev["sw"] = String(version);
|
||||
dev["mf"] = DEVICE_MF;
|
||||
JsonArray ids = dev.createNestedArray("ids");
|
||||
ids.add(chipid);
|
||||
|
||||
String payload;
|
||||
serializeJson(payload_doc, payload);
|
||||
|
||||
|
||||
bool response = ConnectMQTT(broker, MQTT_NAME, MQTT_USER, MQTT_PASSWORD);
|
||||
if (response) {
|
||||
_mqtt_client.publish(_config_topic.c_str(), payload.c_str(), MSG_RETAIN);
|
||||
_mqtt_client.loop();
|
||||
}
|
||||
|
||||
_mqtt_client.subscribe((_topic_root + MODE_SET).c_str());
|
||||
_mqtt_client.subscribe((_topic_root + TEMP_SET).c_str());
|
||||
if (multimode) {
|
||||
_mqtt_client.subscribe((_topic_root + TEMP_HI_SET).c_str());
|
||||
_mqtt_client.subscribe((_topic_root + TEMP_LO_SET).c_str());
|
||||
}
|
||||
|
||||
_mqtt_client.loop();
|
||||
}
|
||||
|
||||
void Device::_Temp(byte value){
|
||||
Serial.print("Set Temp");
|
||||
_temp = value;
|
||||
SendState(TEMP_STATE, (char*)value);
|
||||
}
|
||||
void Device::_Mode(char* value){
|
||||
Serial.print("Set Mode");
|
||||
strcpy(_mode, value);
|
||||
SendState(MODE_STATE, (char*)value);
|
||||
}
|
||||
void Device::_TempHi(byte value){
|
||||
Serial.print("Set High Temp");
|
||||
_temp_hi = value;
|
||||
SendState(TEMP_HI_STATE, (char*)value);
|
||||
}
|
||||
void Device::_TempLo(byte value){
|
||||
Serial.print("Set Low Temp");
|
||||
_temp_lo = value;
|
||||
SendState(TEMP_LO_STATE, (char*)value);
|
||||
}
|
||||
|
||||
void Device::SendState(String suffix, String payload){
|
||||
String topic = _topic_root + suffix;
|
||||
|
||||
_mqtt_client.publish(topic.c_str(), payload.c_str(), MSG_RETAIN);
|
||||
}
|
||||
|
||||
/** Callback function for MQTT client.
|
||||
Looks up a command function based on topic and executes it.
|
||||
|
||||
@param topic
|
||||
@param payload
|
||||
@param length
|
||||
*/
|
||||
void Device::_mqttCallback(char *topic, uint8_t *payload, unsigned int length) {
|
||||
char data [16] = {'\0'};
|
||||
|
||||
// Remove root from the incoming topic.
|
||||
char suffix[100] = topic[_topic_root.length()];
|
||||
Serial.print("Incoming topic -> ");
|
||||
Serial.print(suffix);
|
||||
Serial.print(": ");
|
||||
int i;
|
||||
|
||||
for (i; i < length; i++)
|
||||
{
|
||||
data[i] = ((char)payload[i]);
|
||||
Serial.print(data[i]);
|
||||
}
|
||||
data[i] = '\0';
|
||||
|
||||
switch (suffix) {
|
||||
|
||||
case MODE_SET:
|
||||
_Mode(data);
|
||||
break;
|
||||
|
||||
case TEMP_SET:
|
||||
_Temp(atoi(data));
|
||||
break;
|
||||
|
||||
case TEMP_LO_SET:
|
||||
_TempLo(atoi(data));
|
||||
break;
|
||||
|
||||
case TEMP_HI_SET:
|
||||
_TempHi(atoi(data));
|
||||
break;
|
||||
|
||||
default:
|
||||
Serial.println("Command function not found for " + String(topic));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Connect to MQTT broker.
|
||||
|
||||
@param server IP address string of the server.
|
||||
@param name the name used for this connection
|
||||
@param user MQTT broker username
|
||||
@param password MQTT broker password
|
||||
@return boolean indicating success or failure of connection.
|
||||
*/
|
||||
bool Device::ConnectMQTT(const String &server, const String &name, const String &user, const String &password) {
|
||||
|
||||
_mqtt_client.setServer((server.c_str(), 1883);
|
||||
_mqtt_client.setCallback(&Device::_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;
|
||||
|
||||
}
|
@ -53,13 +53,13 @@ const char version[] = "0.0.1";
|
||||
|
||||
#define TOPIC_LIMIT 4
|
||||
|
||||
//COMMAND_SIGNATURE void (*commandFunction)(uint8_t*) // https://forum.arduino.cc/t/assignment-of-function/528949/3
|
||||
//CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int)
|
||||
typedef void (*ptr)(uint8_t*);
|
||||
//typedef ptr (*pm)();
|
||||
|
||||
const size_t DOC_SIZE = JSON_OBJECT_SIZE(29) + JSON_ARRAY_SIZE(4);
|
||||
|
||||
struct CommandTopic {
|
||||
void (*cmd)(byte*);
|
||||
ptr CmdFunc;
|
||||
String CmdTopic;
|
||||
};
|
||||
|
||||
@ -69,13 +69,18 @@ struct ControlDevice {
|
||||
CommandTopic command_topics[TOPIC_LIMIT];
|
||||
};
|
||||
|
||||
void (*cmd)(byte*) CmdLookup(String command_topic, ControlDevice devices[], int device_count) {
|
||||
ptr CmdLookup(String lookup_topic, ControlDevice devices[], int device_count) {
|
||||
for (int i=0;i<device_count;i++) {
|
||||
ControlDevice this_device = devices[i];
|
||||
for (int j=0;j<TOPIC_LIMIT;j++) {
|
||||
if (this_device.command_topics[j]->CmdTopic == command_topic) return this_device.command_topics[j]->cmd;
|
||||
CommandTopic this_topic = this_device.command_topics[j];
|
||||
String topic = this_topic.CmdTopic;
|
||||
if (topic == lookup_topic) {
|
||||
return this_topic.CmdFunc;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,17 +0,0 @@
|
||||
/* This file is all the stuff I want to be
|
||||
able to change without having to update the
|
||||
source repository.
|
||||
*/
|
||||
|
||||
#ifndef GLOBAL_H
|
||||
#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
|
||||
|
||||
#endif
|
@ -4,8 +4,9 @@
|
||||
|
||||
// My Libraries
|
||||
#include <secrets.h>
|
||||
#include <global.h>
|
||||
#include <Global.h>
|
||||
#include <communicator.h>
|
||||
#include <Device.h>
|
||||
|
||||
String chiller_state = "idle";
|
||||
int tank_setpoint = 28;
|
||||
@ -24,12 +25,6 @@ void mqttCallback(char *topic, byte *payload, unsigned int length) {
|
||||
|
||||
Communicator hass_comm = Communicator(net, &mqttCallback);
|
||||
|
||||
String slugify(String input) {
|
||||
input.toLowerCase();
|
||||
input.replace(" ", "_");
|
||||
return input;
|
||||
}
|
||||
|
||||
void merge(JsonObject dest, JsonObjectConst src) {
|
||||
for (auto kvp : src) {
|
||||
dest[kvp.key()] = kvp.value();
|
||||
@ -41,8 +36,6 @@ void merge(JsonObject dest, JsonObjectConst src) {
|
||||
* Using climate device.
|
||||
*/
|
||||
void climateDevice(String name, boolean multimode=false) {
|
||||
auto chipid = String(ESP.getChipId(), HEX);
|
||||
|
||||
String name_slug = slugify(name);
|
||||
|
||||
String config_topic = "homeassistant/climate/" + name_slug + "_" + chipid + "/config";
|
||||
|
@ -1,79 +0,0 @@
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
class Device {
|
||||
public:
|
||||
|
||||
String device_topic;
|
||||
Communicator hass_comm;
|
||||
|
||||
Device(Communicator& comm, String topic) {
|
||||
this->hass_comm = comm;
|
||||
this->device_topic = topic;
|
||||
}
|
||||
|
||||
|
||||
void addParameter(String id, String value){
|
||||
_params[_paramcount] = Parameter(id, value);
|
||||
_paramcount++
|
||||
}
|
||||
|
||||
void attachEntity(Entity entity){
|
||||
_entities[_entitycount] = entity;
|
||||
_entitycount++;
|
||||
}
|
||||
|
||||
void registerDevice(){
|
||||
|
||||
for (int i=0;i<_entitycount;i++){
|
||||
StaticJsonDocument<512> doc;
|
||||
for (int j=0;j<_entities[i].paramcount;j++) {
|
||||
doc[_entities[i].params[j].getID()] = _entities[i].params[j].getValue();
|
||||
}
|
||||
}
|
||||
JsonObject dev = doc.createNestedObject("dev");
|
||||
for (int i=0; i<_paramcount;i++) {
|
||||
dev[_params[j].getID()] = _params[j].getValue();
|
||||
}
|
||||
|
||||
//Register
|
||||
hass_comm.mqtt_discovery(device_topic, doc);
|
||||
}
|
||||
|
||||
private:
|
||||
Parameter _params[];
|
||||
int _paramcount = 0;
|
||||
Entity _entities[];
|
||||
int _entitycount = 0;
|
||||
|
||||
}
|
||||
|
||||
class Entity {
|
||||
public:
|
||||
Parameter params[];
|
||||
int paramcount = 0;
|
||||
void addParameter(String id, String value){
|
||||
params[paramcount] = Parameter(id, value);
|
||||
paramcount++
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Parameter {
|
||||
public:
|
||||
Parameter(String id, String value){
|
||||
this->_id = id;
|
||||
this->_value = value;
|
||||
}
|
||||
|
||||
String getID(){
|
||||
return this->_id;
|
||||
}
|
||||
|
||||
String getValue(){
|
||||
return this->_value;
|
||||
}
|
||||
|
||||
private:
|
||||
String _id;
|
||||
String _value;
|
||||
}
|
Loading…
Reference in New Issue
Block a user