Brewhouse/lib/mqtt/mqtt.cpp
2023-01-25 21:00:25 -05:00

254 lines
8.0 KiB
C++
Executable File

#include "mqtt.h"
void mqttHA::merge(JsonVariant &dst, JsonVariantConst src)
{
if (src.is<JsonObjectConst>())
{
for (JsonPairConst kvp : src.as<JsonObjectConst>())
{
if (dst[kvp.key()])
merge(dst[kvp.key()], kvp.value());
else
dst[kvp.key()] = kvp.value();
}
}
else
{
dst.set(src);
}
}
String mqttHA::slugify(String input) {
return input.toLowerCase().replace(" ", "_");
}
void mqttHA::publishTemperature(DynamicJsonDocument &device, String &vessle) {
name_slug = slugify(device["name"]);
vessel_slug = slugify(vessel);
String topic = "homeassistant/sensor/" + name_slug + "_" + chipid + "/" + vessel_slug + "_temp/config";
DynamicJsonDocument entity(200);
entity["uniq_id"] = chipid + "_" + vessel_slug + "_temp";
entity["dev_cla"] = "temperature";
entity["name"] = vessle + " Temperature";
entity["unit_of_meas"] = "°" + TEMP_UNIT;
entity["val_tpl"] = "{{ value_json }}";
entity["stat_t"] = "damn_yankee/" + name_slug + "/" + vessel_slug + "_temp";
merge(entity, device)
String payload;
serializeJson(entity, payload)
mqtt_discovery(topic, payload);
}
void mqttHA::mqtt_discovery(const String topic, const String payload) {
bool response = ConnectMQTT(MQTT_BROKER, MQTT_NAME, MQTT_USER, MQTT_PASSWORD);
if (response)
{
mqtt_client.setBufferSize(512);
mqtt_client.publish(topic.c_str(), payload.c_str(), true);
/*
// Passive Sensors
mqtt_client.publish((topic + "boil_temperature/config").c_str(),
("{\"uniq_id\": \"" + chipid + "_boil_temp\"," +
"\"dev_cla\": \"temperature\"," +
"\"name\": \"Boil Temperature\"," +
"\"unit_of_meas\": \"°" + TEMP_UNIT + "\"," +
"\"val_tpl\": \"{{ value_json }}\"," +
"\"stat_t\": \"brewhouse/" + DEVNAME + "/boil_temperature\"," +
device + "}")
.c_str(),
true);
mqtt_client.publish((topic + "mash_temperature/config").c_str(),
("{\"uniq_id\": \"" + chipid + "_mash_temp\"," +
"\"dev_cla\": \"temperature\"," +
"\"name\": \"Mash Temperature\"," +
"\"unit_of_meas\": \"°" + TEMP_UNIT + "\"," +
"\"val_tpl\": \"{{ value_json }}\"," +
"\"stat_t\": \"brewhouse/" + DEVNAME + "/mash_temperature\"," +
device + "}")
.c_str(),
true);
// User Changeable Settings
topic = "homeassistant/number/brewhouse_" + chipid + "/";
mqtt_client.publish((topic + "mash_setpoint/config").c_str(),
("{\"uniq_id\": \"" + chipid + "_mash_setpoint\"," +
"\"dev_cla\": \"temperature\"," +
"\"name\": \"mash Setpoint\"," +
"\"val_tpl\": \"{{ value_json }}\"," +
"\"cmd_tpl\": \"{{ value_json }}\"," +
"\"stat_t\": \"brewhouse/" + DEVNAME + "/mash_setpoint\"," +
"\"cmd_t\": \"brewhouse/" + DEVNAME + "/mash_set_temp\"," +
device + "}")
.c_str(),
true);
mqtt_client.publish((topic + "boil_setpoint/config").c_str(),
("{\"uniq_id\": \"" + chipid + "_boil_setpoint\"," +
"\"dev_cla\": \"temperature\"," +
"\"name\": \"Boil Setpoint\"," +
"\"val_tpl\": \"{{ value_json }}\"," +
"\"cmd_tpl\": \"{{ value_json }}\"," +
"\"stat_t\": \"brewhouse/" + DEVNAME + "/boil_setpoint\"," +
"\"cmd_t\": \"brewhouse/" + DEVNAME + "/boil_set_temp\"," +
device + "}")
.c_str(),
true);
mqtt_client.publish((topic + "boil_pwm/config").c_str(),
("{\"uniq_id\": \"" + chipid + "_boil_pwm\"," +
"\"dev_cla\": \"temperature\"," +
"\"name\": \"Boil pwm\"," +
"\"val_tpl\": \"{{ value_json }}\"," +
"\"cmd_tpl\": \"{{ value_json }}\"," +
"\"stat_t\": \"brewhouse/" + DEVNAME + "/boil_pwm\"," +
"\"cmd_t\": \"brewhouse/" + DEVNAME + "/boil_set_pwm\"," +
device + "}")
.c_str(),
true);
topic = "homeassistant/select/brewhouse_" + chipid + "/";
mqtt_client.publish((topic + "boil_mode/config").c_str(),
("{\"uniq_id\": \"" + chipid + "_boil_mode\"," +
"\"name\": \"Boil Mode\"," +
"\"ops\": [\"PWM\",\"PID\"]," +
"\"val_tpl\": \"{{ value_json }}\"," +
"\"cmd_tpl\": \"{{ value_json }}\"," +
"\"stat_t\": \"brewhouse/" + DEVNAME + "/boil_mode\"," +
"\"cmd_t\": \"brewhouse/" + DEVNAME + "/boil_set_mode\"," +
device + "}")
.c_str(),
true);
*/
mqtt_client.loop();
}
bool mqttHA::ConnectMQTT(const String &server, const String &name, const String &user, const String &password) {
Serial.println("Setup MQTT client.");
mqtt_client.begin(server.c_str(), _net);
mqtt_client.onMessage(MessageReceived);
Serial.println("connecting MQTT...");
byte i = 0;
while (!mqtt_client.connected() && (i < 3)) {
boolean ret;
ret = mqtt_client.connect(name.c_str(), user.c_str(), password.c_str())
if (ret) {
Serial.println("Connected to MQTT");
mqtt_client.subscribe("brewery/setpoint/bk");
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 mqttHA::MessageReceived(String &topic, String &payload) {
Serial.println("incoming: " + topic + " - " + payload);
/** JSON Parser Setup */
StaticJsonDocument<200> doc;
// Deserialize the JSON document
DeserializationError error = deserializeJson(doc, payload);
// Test if parsing succeeds.
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
char buf[30];
strcpy(buf,TOPIC_PREFIX);
strcat(buf,BOIL_SETPOINT_TOPIC);
if (topic == buf) {
// Update PWM setpoint.
String name = doc["entity"];
String setting = doc["setpoint"];
KettleDuty = setting.toInt();
String unit = doc["units"];
Serial.println("Updating setpoint for " + name + " to " + setting + " " + unit);
}
}
static void mqttHA::SendSensorData() {
Serial.println("Sending data...");
// NOTE: max message length is 250 bytes.
StaticJsonDocument<200> doc;
doc["entity"] = "boil_kettle";
doc["setpoint"] = KettleDuty;
doc["units"] = "%";
String jstr;
serializeJson(doc, jstr);
String topic = TOPIC_PREFIX;
topic += "sensor/boil_kettle";
mqtt_client.publish(topic, jstr);
}