diff --git a/src/config.h-example b/src/config.h-example index d3f5cb0..85730c4 100644 --- a/src/config.h-example +++ b/src/config.h-example @@ -9,13 +9,18 @@ // Home Assistant settings +// We need a unique name for the device. +// The following code contains a mapping from MAC address to device name. +// In case no mapping is available for a MAC address, a name will be +// constructed based on the MAC address as a fallback. +// Variables in HA will have names like: .temperature, etc. +DeviceMapping deviceMapping[] = { + { "01:02:03:ab:ba:f0", "my sensor name" } +}; + // You must have already installed Home Assistant on a computer on your // network. Go to www.home-assistant.io for help on this. -// Choose a unique name for this MS430 sensor board so you can identify it. -// Variables in HA will have names like: SENSOR_NAME.temperature, etc. -#define SENSOR_NAME "metriful_living_room" - // Change this to the IP address of the computer running Home Assistant. // You can find this from the admin interface of your router. #define HOME_ASSISTANT_IP "..." diff --git a/src/main.cpp b/src/main.cpp index 8896f1e..f430ecc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,17 @@ #include +#include #include #include + +// A struct that is used in config.h to set a device's name +// based on its WiFi MAC address. The config.h file must configure +// 'DeviceMapping deviceMapping[]', even if it is empty. +struct DeviceMapping +{ + char macAddress[18]; + char deviceName[50]; +}; + #include "config.h" WiFiClient client; @@ -18,7 +29,7 @@ SoundData_t soundData = {0}; // Definition of the display attributes of data sent to Home Assistant. // The attribute fields are: {name, unit, icon, decimal places} -HA_Attributes_t pressure = {"Pressure", "hPa", "weather-cloudy", 0}; +HA_Attributes_t pressure = {"Pressure", "hPa", "weather-cloudy", 1}; HA_Attributes_t humidity = {"Humidity","%","water-percent",1}; HA_Attributes_t temperature = {"Temperature", CELSIUS_SYMBOL, "thermometer", 1}; HA_Attributes_t illuminance = {"Illuminance","lx","white-balance-sunny",2}; @@ -32,11 +43,51 @@ HA_Attributes_t AQ_calibration = {"Air quality calibration","","flower-tulip",0} HA_Attributes_t particleConcentration = {"Particle concentration", "ppL", "chart-bubble", 0}; HA_Attributes_t particleCalibration = {"Particle calibration", "", "chart-bubble", 0}; +// Buffer for storing the device name. +char deviceName[50]; + +void setDeviceName() +{ + byte mac[6]; + char macAddress[18]; + WiFi.macAddress(mac); + snprintf( + macAddress, sizeof(macAddress) / sizeof(macAddress[0]), + "%x:%x:%x:%x:%x:%x", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]); + Serial.print("Device MAC address: "); + Serial.println(macAddress); + + // Set de default device name, based on the MAC address. + // The following code might set a specific device name, + // based on the configuration data. + snprintf(deviceName, sizeof(deviceName), + "metriful_%x%x%x%x%x%x", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]); + + if (sizeof(deviceMapping) > 0) + { + struct DeviceMapping *ptr = deviceMapping; + struct DeviceMapping *last = deviceMapping + sizeof(deviceMapping) / sizeof(deviceMapping[0]); + while (ptr < last) + { + if (strcasecmp(macAddress, ptr->macAddress) == 0) + { + strncpy(deviceName, ptr->deviceName, sizeof(deviceName)); + } + ptr++; + } + } + + Serial.print("Device name: "); + Serial.println(deviceName); +} + void setup() { SensorHardwareSetup(I2C_ADDRESS); connectToWiFi(WIFI_SSID, WIFI_PASSWORD); + setDeviceName(); + // Apply settings to the Metriful MS430 board and enter cycle mode. uint8_t particleSensorCode = PARTICLE_SENSOR; uint8_t cycle_period = CYCLE_PERIOD; @@ -57,7 +108,7 @@ void http_POST_Home_Assistant(const HA_Attributes_t * attributes, const char * v fieldBuffer[i] = '_'; } } - sprintf(postBuffer,"POST /api/states/" SENSOR_NAME ".%s HTTP/1.1", fieldBuffer); + sprintf(postBuffer, "POST /api/states/%s.%s HTTP/1.1", deviceName, fieldBuffer); client.println(postBuffer); client.println("Host: " HOME_ASSISTANT_IP ":8123"); client.println("Content-Type: application/json"); @@ -143,13 +194,25 @@ void send_data_to_home_assistant() { uint8_t T_fractionalPart = 0; bool isPositive = true; getTemperature(&airData, &T_intPart, &T_fractionalPart, &isPositive); - - sendNumericData(&temperature, (uint32_t) T_intPart, T_fractionalPart, isPositive); - sendNumericData(&pressure, (uint32_t)airData.P_Pa / 100, 0, true); - sendNumericData(&humidity, (uint32_t) airData.H_pc_int, airData.H_pc_fr_1dp, true); - sendNumericData(&illuminance, (uint32_t) lightData.illum_lux_int, lightData.illum_lux_fr_2dp, true); - sendNumericData(&soundLevel, (uint32_t) soundData.SPL_dBA_int, soundData.SPL_dBA_fr_1dp, true); - sendNumericData(&peakAmplitude, (uint32_t) soundData.peak_amp_mPa_int, soundData.peak_amp_mPa_fr_2dp, true); + if (T_intPart > 0 || T_fractionalPart > 0) + sendNumericData(&temperature, (uint32_t)T_intPart, T_fractionalPart, isPositive); + + uint32_t P_intPart = airData.P_Pa / 100; + uint32_t P_fractionalPart = floor((airData.P_Pa % 100) / 10 + 0.5); + if (P_intPart > 0 || P_fractionalPart > 0) + sendNumericData(&pressure, P_intPart, P_fractionalPart, true); + + if (airData.H_pc_int > 0 || airData.H_pc_fr_1dp > 0) + sendNumericData(&humidity, (uint32_t) airData.H_pc_int, airData.H_pc_fr_1dp, true); + + if (lightData.illum_lux_int > 0 || lightData.illum_lux_fr_2dp > 0) + sendNumericData(&illuminance, (uint32_t) lightData.illum_lux_int, lightData.illum_lux_fr_2dp, true); + + if (soundData.SPL_dBA_int > 0 || soundData.SPL_dBA_fr_1dp > 0) + sendNumericData(&soundLevel, (uint32_t) soundData.SPL_dBA_int, soundData.SPL_dBA_fr_1dp, true); + + if (soundData.peak_amp_mPa_int > 0 || soundData.peak_amp_mPa_fr_2dp > 0) + sendNumericData(&peakAmplitude, (uint32_t) soundData.peak_amp_mPa_int, soundData.peak_amp_mPa_fr_2dp, true); // When the particle sensor is not connected, we get 65535 readings. // We want to skip those. Also skip sending data while the sensor @@ -173,8 +236,13 @@ void send_data_to_home_assistant() { } void log_measurements_to_console() { + Serial.println(""); printAirData(&airData, false); + printAirQualityData(&airQualityData, false); + printLightData(&lightData, false); + printSoundData(&soundData, false); printParticleData(&particleData, false, PARTICLE_SENSOR); + Serial.println(""); } void loop()