Skip to content

Commit

Permalink
Update CO2_Gadget_Battery.h, README.md, platformio.ini, CO2_Gadget_WI…
Browse files Browse the repository at this point in the history
…FI.h, and CO2_Gadget.ino
  • Loading branch information
melkati committed Jan 10, 2024
2 parents cf4a49a + ae05ae8 commit 565f1ad
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 30 deletions.
17 changes: 16 additions & 1 deletion CO2_Gadget.ino
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
// Next data always defined to be able to configure in menu
String hostName = UNITHOSTNAME;
String rootTopic = UNITHOSTNAME;
String discoveryTopic = MQTT_DISCOVERY_PREFIX;
String mqttClientId = UNITHOSTNAME;
String mqttBroker = MQTT_BROKER_SERVER;
String mqttUser = "";
String mqttPass = "";
String wifiSSID = WIFI_SSID_CREDENTIALS;
String wifiPass = WIFI_PW_CREDENTIALS;
String mDNSName = "Unset";
String MACAddress = "Unset";
// String peerESPNow = ESPNOW_PEER_MAC_ADDRESS;
uint8_t peerESPNowAddress[] = ESPNOW_PEER_MAC_ADDRESS;

Expand All @@ -41,6 +43,7 @@ uint64_t timeToRetryTroubledWIFI = 300; // Time in seconds to retry WIFI connec
uint64_t timeToRetryTroubledMQTT = 900; // Time in seconds to retry MQTT connection after it is troubled (no need to retry so often as it retries automatically after WiFi is connected)
uint16_t WiFiConnectionRetries = 0;
uint16_t maxWiFiConnectionRetries = 5;
bool mqttDiscoverySent = false;

// Display and menu options
uint32_t DisplayBrightness = 100;
Expand All @@ -63,6 +66,7 @@ uint16_t boardIdESPNow = 0;

// Variables for Battery reading
float battery_voltage = 0;
uint8_t battery_level = 0;
uint16_t timeBetweenBatteryRead = 15;
uint64_t lastTimeBatteryRead = 0; // Time of last battery reading

Expand Down Expand Up @@ -229,6 +233,7 @@ uint16_t batteryFullyChargedMillivolts = 4200; // Voltage of battery when it is
/********* SETUP PUSH BUTTONS FUNCTIONALITY *********/
/********* *********/
/*****************************************************************************************************/
#include "Arduino.h"
#include "CO2_Gadget_Buttons.h"

/*****************************************************************************************************/
Expand Down Expand Up @@ -366,6 +371,15 @@ void displayLoop() {
}
}

void batteryLoop() {
const float lastBatteryVoltage = battery_voltage;
readBatteryVoltage();
if (abs(lastBatteryVoltage - battery_voltage) >= 0.1) { // If battery voltage changed by at least 0.1, update battery level
battery_level = getBatteryPercentage();
Serial.printf("-->[BATT] Battery Level: %d%%\n", battery.level());
}
}

void utilityLoop() {
if (battery_voltage > 4.5) {
setCpuFrequencyMhz(240); // High CPU frecuency when working on USB power
Expand Down Expand Up @@ -411,6 +425,7 @@ void setup() {
}

void loop() {
batteryLoop();
wifiClientLoop();
mqttClientLoop();
sensorsLoop();
Expand All @@ -426,4 +441,4 @@ void loop() {
#ifdef SUPPORT_BLE
BLELoop();
#endif
}
}
1 change: 0 additions & 1 deletion CO2_Gadget_Battery.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ float readBatteryVoltage() {
}

uint8_t getBatteryPercentage() {
Serial.printf("-->[BATT] Battery Level: %d%%\n", battery.level());
return battery.level();
}

Expand Down
150 changes: 144 additions & 6 deletions CO2_Gadget_MQTT.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,16 +113,130 @@ void publishFloatMQTT(String topic, float payload) {

void publishStrMQTT(String topic, String payload) {
#ifdef SUPPORT_MQTT
payload.toCharArray(charPublish, payload.length());
topic = rootTopic + topic;
if (!inMenu) {
Serial.printf("-->[MQTT] Publishing %s to ", payload);
Serial.printf("-->[MQTT] Publishing %s to ", payload.c_str());
Serial.println("topic: " + topic);
mqttClient.publish((topic).c_str(), charPublish);
mqttClient.publish(topic.c_str(), payload.c_str());
}
#endif
}

void publishStrDiscoveryMQTT(String topic, String payload, int qos) {
#ifdef SUPPORT_MQTT
if (!inMenu) {
Serial.printf("-->[MQTT] Publishing %s to ", payload.c_str());
Serial.println("topic: " + topic);
mqttClient.publish(topic.c_str(), payload.c_str(), true);
}
#endif
}

bool sendMQTTDiscoveryTopic(String deviceClass, String stateClass, String entityCategory,
String group, String field, String name, String icon, String unit,
int qos) {
String version = String(CO2_GADGET_VERSION) + String(CO2_GADGET_REV) + " (" + String(FLAVOUR) + ")";
String hw_version = String(FLAVOUR);

String maintopic = String(rootTopic);

String topicFull;
String configTopic;
String payload;

configTopic = field;

if (field == "problem") { // Special binary sensor which is based on error topic
topicFull = discoveryTopic + "binary_sensor/" + maintopic + "/" + configTopic + "/config";
} else {
topicFull = discoveryTopic + "sensor/" + maintopic + "/" + configTopic + "/config";
}

/* See https://www.home-assistant.io/docs/mqtt/discovery/ */
payload = String("{") +
"\"~\": \"" + maintopic + "\"," +
"\"unique_id\": \"" + maintopic + "-" + configTopic + "\"," +
"\"object_id\": \"" + maintopic + "_" + configTopic + "\"," +
"\"name\": \"" + name + "\"," +
"\"icon\": \"mdi:" + icon + "\"," +
"\"unit_of_measurement\": \"" + unit + "\",";

if (field == "problem") { // Special binary sensor which is based on error topic
payload += "\"state_topic\": \"~/error\",";
payload += "\"value_template\": \"{{ 'OFF' if 'no error' in value else 'ON'}}\",";
} else {
payload += "\"state_topic\": \"~/" + field + "\",";
}

if (deviceClass != "") {
payload += "\"device_class\": \"" + deviceClass + "\",";
}

if (stateClass != "") {
payload += "\"state_class\": \"" + stateClass + "\",";
}

if (entityCategory != "") {
payload += "\"entity_category\": \"" + entityCategory + "\",";
}

payload += String("\"device\": {") +
"\"identifiers\": [\"" + maintopic + "\"]," +
"\"name\": \"" + maintopic + "\"," +
"\"model\": \"CO2 Gadget\"," +
"\"manufacturer\": \"emariete.com\"," +
"\"hw_version\": \"" + hw_version + "\"," +
"\"sw_version\": \"" + version + "\"," +
"\"configuration_url\": \"http://" + WiFi.localIP().toString() + "\"" +
"}" +
"}";

// Replace the following line with your MQTT publish function
// return MQTTPublish(topicFull, payload, qos, true);
Serial.print("MQTT Publish Topic: ");
Serial.println(topicFull);
Serial.print("MQTT Publish Payload: ");
Serial.println(payload);
// topicFull = "Test";
// payload = "Test";
publishStrDiscoveryMQTT(topicFull, payload, qos);
return true;
}

bool publishMQTTDiscovery(int qos) {
bool allSendsSuccessed = false;

if (!mqttClient.connected()) {
Serial.println("Unable to send MQTT Discovery Topics, we are not connected to the MQTT broker!");
return false;
}

// clang-format off
// TO-DO: Add MAC Address, Hostname, IP and Status to discovery. Don't know why they are not working (home assistant doesn't show them)
//
// Device Class | State Class | Entity Category | Group | Field | User Friendly Name | Icon | Unit
allSendsSuccessed |= sendMQTTDiscoveryTopic("", "", "diagnostic", "", "uptime", "Uptime", "clock-time-eight-outline", "s", qos);
// allSendsSuccessed |= sendMQTTDiscoveryTopic("", "", "diagnostic", "", "MAC", "MAC Address", "network-outline", "", qos);
// allSendsSuccessed |= sendMQTTDiscoveryTopic("", "", "diagnostic", "", "hostname", "Hostname", "network-outline", "", qos);
allSendsSuccessed |= sendMQTTDiscoveryTopic("", "measurement", "diagnostic", "", "freeMem", "Free Memory", "memory", "B", qos);
allSendsSuccessed |= sendMQTTDiscoveryTopic("", "", "diagnostic", "", "wifiRSSI", "Wi-Fi RSSI", "wifi", "dBm", qos);
// allSendsSuccessed |= sendMQTTDiscoveryTopic("", "", "diagnostic", "", "IP", "IP", "network-outline", "", qos);
// allSendsSuccessed |= sendMQTTDiscoveryTopic("", "", "diagnostic", "", "status", "Status", "list-status", "", qos);
allSendsSuccessed |= sendMQTTDiscoveryTopic("", "measurement", "diagnostic", "", "battery", "Battery", "", "%", qos);
allSendsSuccessed |= sendMQTTDiscoveryTopic("", "measurement", "diagnostic", "", "voltage", "Voltage", "", "V", qos);

allSendsSuccessed |= sendMQTTDiscoveryTopic("carbon_dioxide", "", "", "", "co2", "CO2", "molecule-co2", "ppm", qos);
allSendsSuccessed |= sendMQTTDiscoveryTopic("temperature", "", "", "", "temp", "Temperature", "temperature-celsius", "°C", qos);
allSendsSuccessed |= sendMQTTDiscoveryTopic("humidity", "", "", "", "humi", "Humidity", "water-percent", "%", qos);
// allSendsSuccessed |= sendMQTTDiscoveryTopic("", "", "diagnostic", "", "error", "Error", "alert-circle-outline", "", qos);
// allSendsSuccessed |= sendMQTTDiscoveryTopic("", "", "diagnostic", "", "json", "JSON", "code-json", "", qos);
// allSendsSuccessed |= sendMQTTDiscoveryTopic("", "", "", "", "problem", "Problem", "alert-outline", "", qos); // Special binary sensor which is based on error topic
// clang-format on

Serial.println("Successfully published all MQTT Discovery topics");
return allSendsSuccessed;
}

void initMQTT() {
#ifdef SUPPORT_MQTT
if (activeMQTT) {
Expand All @@ -136,6 +250,7 @@ void initMQTT() {
Serial.printf("-->[MQTT] Initializing MQTT to broker IP: %s\n", mqttBroker.c_str());
mqttClient.setServer(mqttBroker.c_str(), 1883);
mqttClient.setCallback(callbackMQTT);
mqttClient.setBufferSize(1024);
mqttReconnect();
}
#endif
Expand Down Expand Up @@ -170,15 +285,32 @@ void publishMQTTAlarms() {
}
}

void publishMQTTSystemData() {
publishIntMQTT("/uptime", millis() / 1000);
publishFloatMQTT("/voltage", battery_voltage);
publishIntMQTT("/battery", battery_level);
publishIntMQTT("/freeMem", ESP.getFreeHeap());
publishIntMQTT("/wifiRSSI", WiFi.RSSI());
publishStrMQTT("/IP", WiFi.localIP().toString());
publishStrMQTT("/MAC", WiFi.macAddress());
publishStrMQTT("/hostname", hostName);
publishStrMQTT("/status", "OK");
}

void publishMeasurementsMQTT() {
publishIntMQTT("/co2", co2);
publishFloatMQTT("/temp", temp);
publishFloatMQTT("/humi", hum);
}

void publishMQTT() {
#ifdef SUPPORT_MQTT
if (activeMQTT) {
if ((WiFi.status() == WL_CONNECTED) && (mqttClient.connected())) {
if (millis() - lastTimeMQTTPublished >= timeBetweenMQTTPublish * 1000) {
publishIntMQTT("/co2", co2);
publishFloatMQTT("/temp", temp);
publishFloatMQTT("/humi", hum);
publishMeasurementsMQTT();
publishMQTTAlarms();
publishMQTTSystemData();
lastTimeMQTTPublished = millis();
}
// Serial.print("-->[MQTT] Free heap: ");
Expand All @@ -201,6 +333,12 @@ void mqttClientLoop() {
mqttClient.loop();
}
}

if (!mqttDiscoverySent && mqttClient.connected()) {
Serial.printf("-->[MQTT] Connected to broker. Sending discovery...\n");
publishMQTTDiscovery(0);
mqttDiscoverySent = true;
}
#endif
}

Expand Down
37 changes: 18 additions & 19 deletions CO2_Gadget_WIFI.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@ void onWifiSettingsChanged(std::string ssid, std::string password) {
WiFi.begin(ssid.c_str(), password.c_str());
}

String getMACAddressAsString() {
byte mac[6];
WiFi.macAddress(mac);

String macAddress = String(mac[5], HEX) + ":" +
String(mac[4], HEX) + ":" +
String(mac[3], HEX) + ":" +
String(mac[2], HEX) + ":" +
String(mac[1], HEX) + ":" +
String(mac[0], HEX);

return macAddress;
}

void printWiFiStatus() { // Print wifi status on serial monitor

// Get current status
Expand Down Expand Up @@ -78,7 +92,8 @@ void printWiFiStatus() { // Print wifi status on serial monitor

// Print your WiFi shield's MAC address:
Serial.print("-->[WiFi] MAC Address: ");
Serial.println(WiFi.macAddress());
MACAddress = getMACAddressAsString();
Serial.println(MACAddress);

// Print the received signal strength:
Serial.print("-->[WiFi] Signal strength (RSSI):");
Expand Down Expand Up @@ -234,23 +249,6 @@ String processor(const String &var) {
return String();
}

void serialPrintMACAddress() {
byte mac[6];
WiFi.macAddress(mac);
Serial.print("-->[WiFi] MAC: ");
Serial.print(mac[5], HEX);
Serial.print(":");
Serial.print(mac[4], HEX);
Serial.print(":");
Serial.print(mac[3], HEX);
Serial.print(":");
Serial.print(mac[2], HEX);
Serial.print(":");
Serial.print(mac[1], HEX);
Serial.print(":");
Serial.println(mac[0], HEX);
}

bool checkStringIsNumerical(String myString) {
uint16_t Numbers = 0;

Expand Down Expand Up @@ -375,7 +373,8 @@ void initWifi() {
}
}
Serial.println("");
serialPrintMACAddress();
Serial.print("-->[WiFi] MAC: ");
Serial.println(MACAddress);
Serial.print("-->[WiFi] WiFi connected - IP = ");
Serial.println(WiFi.localIP());
#ifdef SUPPORT_MDNS
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ This repository is mainly addressed at developers. If you are an end user willin
- WIFI connection
- Sending of data via MQTT
- Receiving remote commands via MQTT
- MQTT Discovery protocol for Home Assistant (and others supporting it as HomeSeer with mcsMQTT)
- ESP-NOW communications protocol from Espressif for long range and low power consuption ([more info here](https://emariete.com/en/gateway-esp-now-mqtt/))
- Over the air updates OTA
- Support for Neopixel (WS2812B) addressable LEDs (RGB, GBR and RGBW)
Expand Down
9 changes: 6 additions & 3 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ build_flags =

-D MQTT_BROKER_SERVER="\"192.168.1.145"\"
-D CO2_GADGET_VERSION="\"0.7."\"
-D CO2_GADGET_REV="\"008"\"
-D CORE_DEBUG_LEVEL=0
-D CO2_GADGET_REV="\"010"\"
-D CORE_DEBUG_LEVEL=0
-DNEOPIXEL_PIN=26 ; Pinnumber for button for down/next and back / exit actions
-DNEOPIXEL_COUNT=16 ; How many neopixels to control
-DENABLE_PIN=27 ; Reserved for the future to enable the sensor
Expand All @@ -72,6 +72,9 @@ build_flags =
; -DSUPPORT_OTA ; Needs SUPPORT_WIFI
; -DSUPPORT_MDNS ; Needs SUPPORT_WIFI
-DSUPPORT_MQTT ; Needs SUPPORT_WIFI
-DSUPPORT_MQTT_DISCOVERY
-DMQTT_DISCOVERY_PREFIX="\"homeassistant/\""

-DSUPPORT_ESPNOW
-DESPNOW_PEER_MAC_ADDRESS="{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}" ; MAC Address of the ESP-NOW receiver (STA MAC). For unicast use peer address, as: {0xE8, 0x68, 0xE7, 0x0F, 0x08, 0x90}
-DESPNOW_WIFI_CH=1 ; ESP-NOW WiFi Channel. Must be same as gateway
Expand Down Expand Up @@ -260,4 +263,4 @@ build_flags =
-DFLAVOUR="\"ESP32 OLED OTA"\"
-USUPPORT_BLE
-DSUPPORT_OTA
-DSUPPORT_MDNS
-DSUPPORT_MDNS

0 comments on commit 565f1ad

Please sign in to comment.