Don't report unreliable data. Also translate Pa -> hPa, which is a more commonly used unit.

This commit is contained in:
Maurice Makaay 2021-01-08 02:01:24 +01:00
parent 0767d1661f
commit d67511fbb5
2 changed files with 74 additions and 69 deletions

View File

@ -15,17 +15,13 @@ monitor_speed = 9600
platform = atmelsam
board = nano_33_iot
framework = arduino
lib_deps =
WiFiNINA
MQTT
WiFiNINA
MQTT
[env:d1_mini]
platform = espressif8266
board = d1_mini
framework = arduino
upload_protocol = esptool
lib_deps =
MQTT
lib_deps = MQTT

View File

@ -3,58 +3,41 @@
#include <WiFi_functions.h>
#include "config.h"
#if !defined(HAS_WIFI)
#error ("This example program has been created for specific WiFi enabled hosts only.")
#endif
WiFiClient client;
// Buffers for assembling http POST requests
// Buffers for assembling http POST requests.
char postBuffer[450] = {0};
char fieldBuffer[70] = {0};
// Structs for data
// Structs for holding measurement data.
AirData_t airData = {0};
AirQualityData_t airQualityData = {0};
LightData_t lightData = {0};
ParticleData_t particleData = {0};
SoundData_t soundData = {0};
// Define the display attributes of data sent to Home Assistant.
// The chosen name, unit and icon will appear in on the overview
// dashboard in Home Assistant. The icons can be chosen from
// https://cdn.materialdesignicons.com/5.3.45/
// (remove the "mdi-" part from the icon name).
// 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","Pa","weather-cloudy",0};
HA_Attributes_t pressure = {"Pressure", "hPa", "weather-cloudy", 0};
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};
HA_Attributes_t soundLevel = {"Sound level","dBA","microphone",1};
HA_Attributes_t peakAmplitude = {"Sound peak","mPa","waveform",2};
HA_Attributes_t estimatedCO2 = {"Estimated CO2","ppm","chart-bubble",1};
HA_Attributes_t equivalentBreathVOC = {"Equivalent breath VOC","ppm","chart-bubble",2};
HA_Attributes_t AQI = {"Air Quality Index"," ","thought-bubble-outline",1};
HA_Attributes_t AQ_index = {"Air Quality Index", " ", "thought-bubble-outline", 1};
HA_Attributes_t AQ_assessment = {"Air quality assessment","","flower-tulip",0};
HA_Attributes_t AQ_calibration = {"Air quality calibration","","flower-tulip",0};
#if (PARTICLE_SENSOR == PARTICLE_SENSOR_PPD42)
HA_Attributes_t particulates = {"Particle concentration","ppL","chart-bubble",0};
#else
HA_Attributes_t particulates = {"Particle concentration",SDS011_UNIT_SYMBOL,"chart-bubble",2};
#endif
#ifdef USE_FAHRENHEIT
HA_Attributes_t temperature = {"Temperature",FAHRENHEIT_SYMBOL,"thermometer",1};
#else
HA_Attributes_t temperature = {"Temperature",CELSIUS_SYMBOL,"thermometer",1};
#endif
HA_Attributes_t particleConcentration = {"Particle concentration", "ppL", "chart-bubble", 0};
HA_Attributes_t particleCalibration = {"Particle calibration", "", "chart-bubble", 0};
void setup() {
// Initialize the host's pins, set up the serial port and reset:
void setup()
{
SensorHardwareSetup(I2C_ADDRESS);
connectToWiFi(WIFI_SSID, WIFI_PASSWORD);
// Apply settings to the MS430 and enter cycle mode
// Apply settings to the Metriful MS430 board and enter cycle mode.
uint8_t particleSensorCode = PARTICLE_SENSOR;
uint8_t cycle_period = CYCLE_PERIOD;
TransmitI2C(I2C_ADDRESS, PARTICLE_SENSOR_SELECT_REG, &particleSensorCode, 1);
@ -63,12 +46,12 @@ void setup() {
TransmitI2C(I2C_ADDRESS, CYCLE_MODE_CMD, 0, 0);
}
// Send the data to Home Assistant as an HTTP POST request.
// Send data to Home Assistant as an HTTP POST request.
void http_POST_Home_Assistant(const HA_Attributes_t * attributes, const char * valueText) {
client.stop();
if (client.connect(HOME_ASSISTANT_IP, 8123)) {
// Form the URL from the name but replace spaces with underscores
strcpy(fieldBuffer,attributes->name);
strcpy(fieldBuffer, attributes->name);
for (uint8_t i=0; i<strlen(fieldBuffer); i++) {
if (fieldBuffer[i] == ' ') {
fieldBuffer[i] = '_';
@ -81,9 +64,10 @@ void http_POST_Home_Assistant(const HA_Attributes_t * attributes, const char * v
client.println("Authorization: Bearer " LONG_LIVED_ACCESS_TOKEN);
// Assemble the JSON content string:
sprintf(postBuffer,"{\"state\":%s,\"attributes\":{\"unit_of_measurement\""
":\"%s\",\"friendly_name\":\"%s\",\"icon\":\"mdi:%s\"}}",
valueText, attributes->unit, attributes->name, attributes->icon);
sprintf(postBuffer,
"{\"state\":%s,\"attributes\":{\"unit_of_measurement\""
":\"%s\",\"friendly_name\":\"%s\",\"icon\":\"mdi:%s\"}}",
valueText, attributes->unit, attributes->name, attributes->icon);
sprintf(fieldBuffer,"Content-Length: %u", strlen(postBuffer));
client.println(fieldBuffer);
@ -95,7 +79,7 @@ void http_POST_Home_Assistant(const HA_Attributes_t * attributes, const char * v
}
}
// Send numeric data with specified sign, integer and fractional parts
// Send numeric data with specified sign, integer and fractional parts.
void sendNumericData(const HA_Attributes_t * attributes, uint32_t valueInteger,
uint8_t valueDecimal, bool isPositive) {
char valueText[20] = {0};
@ -115,22 +99,24 @@ void sendNumericData(const HA_Attributes_t * attributes, uint32_t valueInteger,
http_POST_Home_Assistant(attributes, valueText);
}
// Send a text string: must have quotation marks added
// Send a text string: must have quotation marks added.
void sendTextData(const HA_Attributes_t * attributes, const char * valueText) {
char quotedText[20] = {0};
sprintf(quotedText,"\"%s\"", valueText);
http_POST_Home_Assistant(attributes, quotedText);
}
void loop() {
// Wait for the next new data release, indicated by a falling edge on READY
Serial.println("Waiting for new data ...");
void wait_for_new_readings()
{
Serial.println("Waiting for new data from sensors ...");
while (!ready_assertion_event) {
yield();
}
ready_assertion_event = false;
}
void read_sensor_data_from_i2c()
{
// Read data from the MS430 into the data structs.
Serial.println("Reading data from sensors");
ReceiveI2C(I2C_ADDRESS, AIR_DATA_READ, (uint8_t *) &airData, AIR_DATA_BYTES);
@ -138,41 +124,64 @@ void loop() {
ReceiveI2C(I2C_ADDRESS, LIGHT_DATA_READ, (uint8_t *) &lightData, LIGHT_DATA_BYTES);
ReceiveI2C(I2C_ADDRESS, SOUND_DATA_READ, (uint8_t *) &soundData, SOUND_DATA_BYTES);
ReceiveI2C(I2C_ADDRESS, PARTICLE_DATA_READ, (uint8_t *) &particleData, PARTICLE_DATA_BYTES);
}
// Check that WiFi is still connected
void make_sure_wifi_is_connected() {
uint8_t wifiStatus = WiFi.status();
if (wifiStatus != WL_CONNECTED) {
// There is a problem with the WiFi connection: attempt to reconnect.
Serial.print("Wifi status: ");
Serial.print("Wifi diconnected! Status: ");
Serial.println(interpret_WiFi_status(wifiStatus));
connectToWiFi(WIFI_SSID, WIFI_PASSWORD);
ready_assertion_event = false;
}
}
void send_data_to_home_assistant() {
Serial.println("Send data to Home Assistant");
uint8_t T_intPart = 0;
uint8_t T_fractionalPart = 0;
bool isPositive = true;
getTemperature(&airData, &T_intPart, &T_fractionalPart, &isPositive);
// Send data to Home Assistant
Serial.println("Send data to Home Assistant");
sendNumericData(&temperature, (uint32_t) T_intPart, T_fractionalPart, isPositive);
sendNumericData(&pressure, (uint32_t) airData.P_Pa, 0, true);
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);
sendNumericData(&AQI, (uint32_t) airQualityData.AQI_int, airQualityData.AQI_fr_1dp, true);
if (PARTICLE_SENSOR != PARTICLE_SENSOR_OFF) {
sendNumericData(&particulates, (uint32_t) particleData.concentration_int,
particleData.concentration_fr_2dp, true);
}
sendTextData(&AQ_assessment, interpret_AQI_value(airQualityData.AQI_int));
sendNumericData(&estimatedCO2, (uint32_t) airQualityData.CO2e_int, airQualityData.CO2e_fr_1dp, true);
sendNumericData(&equivalentBreathVOC, (uint32_t) airQualityData.bVOC_int, airQualityData.bVOC_fr_2dp, true);
sendNumericData(&AQ_calibration, airQualityData.AQI_accuracy, 0, true);
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
// is warming up. This way, invalid data is not logged in
// Home Assistant.
sendNumericData(&particleCalibration, (uint32_t)particleData.valid, 0, true);
if (particleData.valid != 0 && particleData.concentration_int < 60000)
{
sendNumericData(&particleConcentration, (uint32_t)particleData.concentration_int, particleData.concentration_fr_2dp, true);
}
// While the Metriful board is still in its self-calibration
// phase, do not send air quality data to Home Assistant.
sendNumericData(&AQ_calibration, airQualityData.AQI_accuracy, 0, true);
if (airQualityData.AQI_accuracy > 0) {
sendNumericData(&estimatedCO2, (uint32_t) airQualityData.CO2e_int, airQualityData.CO2e_fr_1dp, true);
sendNumericData(&equivalentBreathVOC, (uint32_t) airQualityData.bVOC_int, airQualityData.bVOC_fr_2dp, true);
sendNumericData(&AQ_index, (uint32_t)airQualityData.AQI_int, airQualityData.AQI_fr_1dp, true);
sendTextData(&AQ_assessment, interpret_AQI_value(airQualityData.AQI_int));
}
}
void log_measurements_to_console() {
printAirData(&airData, false);
printParticleData(&particleData, false, PARTICLE_SENSOR);
}
void loop()
{
wait_for_new_readings();
read_sensor_data_from_i2c();
make_sure_wifi_is_connected();
send_data_to_home_assistant();
log_measurements_to_console();
}