added feature_pms

This commit is contained in:
2021-10-04 13:23:09 +02:00
parent ce150920fe
commit 4d52fc15af
13 changed files with 269 additions and 54 deletions

6
.gitmodules vendored
View File

@ -46,3 +46,9 @@
[submodule "components/esphttpdutils"]
path = components/esphttpdutils
url = git@github.com:0xFEEDC0DE64/esphttpdutils.git
[submodule "components/espconfiglib"]
path = components/espconfiglib
url = git@github.com:0xFEEDC0DE64/espconfiglib.git
[submodule "components/ArduinoJson"]
path = components/ArduinoJson
url = git@github.com:0xFEEDC0DE64/ArduinoJson.git

View File

@ -1,57 +1,10 @@
if [[ $_ == $0 ]] && [[ "$1" != "--skip-source-check" ]]
then
echo "export.sh has to be sourced, not run in a subshell"
echo ". export.sh"
exit 1
fi
DECKENLAMPE_ROOT="$(dirname "$BASH_SOURCE")"
GOE_ROOT="$(dirname "$BASH_SOURCE")"
if [[ ! -f "${GOE_ROOT}/esp-idf/export.sh" ]]
if [[ ! -f "${DECKENLAMPE_ROOT}/esp-idf/export.sh" ]]
then
echo "esp-idf is missing, please check out all needed submodules!"
echo "git submodule update --init --recursive"
return
fi
. ${GOE_ROOT}/esp-idf/export.sh
complete -W "$(./switchconf.sh --list)" ./switchconf.sh
GOE_INIT_FAILED=
if [[ -e "build" ]] && [[ ! -L "build" ]]
then
echo "ERROR: build folder exists but isnt a symlink!"
GOE_INIT_FAILED=1
fi
if [[ -e "sdkconfig" ]]
then
if [[ ! -L "sdkconfig" ]]
then
echo "ERROR: sdkconfig exists but isnt a symlink!"
GOE_INIT_FAILED=1
fi
else
echo "ERROR: sdkconfig does not exist"
GOE_INIT_FAILED=1
fi
if [[ -e "config.cmake" ]]
then
if [[ ! -L "config.cmake" ]]
then
echo "ERROR: config.cmake exists but isnt a symlink!"
GOE_INIT_FAILED=1
fi
else
echo "ERROR: config.cmake does not exist"
GOE_INIT_FAILED=1
fi
if [[ ! -z "$GOE_INIT_FAILED" ]]
then
echo "run ./switchconf.sh to fix all listed issues"
return
fi
. ${DECKENLAMPE_ROOT}/esp-idf/export.sh

View File

@ -6,6 +6,7 @@ set(headers
feature_bmp.h
feature_dht.h
feature_lamp.h
feature_pms.h
feature_switch.h
feature_tsl.h
myble.h
@ -23,6 +24,7 @@ set(sources
feature_bmp.cpp
feature_dht.cpp
feature_lamp.cpp
feature_pms.cpp
feature_switch.cpp
feature_tsl.cpp
main.cpp
@ -38,8 +40,8 @@ set(sources
set(dependencies
freertos nvs_flash esp_http_server esp_https_ota mdns app_update esp_system mqtt
arduino-esp32 date esp-nimble-cpp expected fmt
Adafruit_BMP085_Unified Adafruit_TSL2561 DHT-sensor-library
cpputils espasyncota espchrono espcpputils esphttpdutils espwifistack
airgradient Adafruit_BMP085_Unified Adafruit_TSL2561 DHT-sensor-library
cpputils espasyncota espchrono espconfiglib espcpputils esphttpdutils espwifistack
)
idf_component_register(

196
main/feature_pms.cpp Normal file
View File

@ -0,0 +1,196 @@
#include "feature_pms.h"
// esp-idf includes
#include <esp_log.h>
// Arduino includes
#include <Arduino.h>
#include <HardwareSerial.h>
// 3rdparty lib includes
#include <espstrutils.h>
#include <espchrono.h>
// local includes
#include "myconfig.h"
#include "mymqtt.h"
using namespace std::chrono_literals;
namespace deckenlampe {
namespace {
constexpr const char * const TAG = "PMS";
espchrono::millis_clock::time_point lastRequest;
struct DATA {
// Standard Particles, CF=1
uint16_t PM_SP_UG_1_0;
uint16_t PM_SP_UG_2_5;
uint16_t PM_SP_UG_10_0;
// Atmospheric environment
uint16_t PM_AE_UG_1_0;
uint16_t PM_AE_UG_2_5;
uint16_t PM_AE_UG_10_0;
} pms_data;
uint8_t pms_payload[12];
uint8_t pms_index = 0;
uint16_t pms_frameLen;
uint16_t pms_checksum;
uint16_t pms_calculatedChecksum;
}
void init_pms()
{
if (!config::enable_pms.value())
return;
ESP_LOGI(TAG, "starting Serial1 for PMS %i %i", config::pins_pms_rx.value(), config::pins_pms_tx.value());
Serial1.begin(9600, SERIAL_8N1, config::pins_pms_rx.value(), config::pins_pms_tx.value());
{
ESP_LOGI(TAG, "setting into active mode...");
uint8_t command[] = { 0x42, 0x4D, 0xE1, 0x00, 0x01, 0x01, 0x71 };
Serial1.write({command, sizeof(command)});
}
}
void update_pms()
{
if (!config::enable_pms.value())
return;
if (espchrono::ago(lastRequest) >= 1s)
{
lastRequest = espchrono::millis_clock::now();
if (false)
{
ESP_LOGI(TAG, "setting into active mode...");
uint8_t command[] = { 0x42, 0x4D, 0xE1, 0x00, 0x01, 0x01, 0x71 };
Serial1.write({command, sizeof(command)});
}
if (false)
{
ESP_LOGI(TAG, "setting into passive mode...");
uint8_t command[] = { 0x42, 0x4D, 0xE1, 0x00, 0x00, 0x01, 0x70 };
Serial1.write({command, sizeof(command)});
}
if (false)
{
ESP_LOGI(TAG, "requesting read...");
uint8_t command[] = { 0x42, 0x4D, 0xE2, 0x00, 0x00, 0x01, 0x71 };
Serial1.write({command, sizeof(command)});
}
}
if (false)
{
uint8_t buf[256];
if (const auto read = Serial1.read(buf, sizeof(buf)))
{
ESP_LOGI(TAG, "received %zd %s", read, espcpputils::toHexString({buf, read}).c_str());
}
}
if (Serial1.available())
{
uint8_t ch = Serial1.read();
switch (pms_index)
{
case 0:
if (ch != 0x42)
return;
pms_calculatedChecksum = ch;
break;
case 1:
if (ch != 0x4D)
{
pms_index = 0;
return;
}
pms_calculatedChecksum += ch;
break;
case 2:
pms_calculatedChecksum += ch;
pms_frameLen = ch << 8;
break;
case 3:
pms_frameLen |= ch;
// Unsupported sensor, different frame length, transmission error e.t.c.
if (pms_frameLen != 2 * 9 + 2 && pms_frameLen != 2 * 13 + 2)
{
pms_index = 0;
return;
}
pms_calculatedChecksum += ch;
break;
default:
if (pms_index == pms_frameLen + 2)
{
pms_checksum = ch << 8;
}
else if (pms_index == pms_frameLen + 2 + 1)
{
pms_checksum |= ch;
if (pms_calculatedChecksum == pms_checksum)
{
//_PMSstatus = STATUS_OK;
// Standard Particles, CF=1.
pms_data.PM_SP_UG_1_0 = makeWord(pms_payload[0], pms_payload[1]);
pms_data.PM_SP_UG_2_5 = makeWord(pms_payload[2], pms_payload[3]);
pms_data.PM_SP_UG_10_0 = makeWord(pms_payload[4], pms_payload[5]);
// Atmospheric Environment.
pms_data.PM_AE_UG_1_0 = makeWord(pms_payload[6], pms_payload[7]);
pms_data.PM_AE_UG_2_5 = makeWord(pms_payload[8], pms_payload[9]);
pms_data.PM_AE_UG_10_0 = makeWord(pms_payload[10], pms_payload[11]);
ESP_LOGI(TAG, "PM_SP_UG_1_0 %hu", pms_data.PM_SP_UG_1_0);
ESP_LOGI(TAG, "PM_SP_UG_2_5 %hu", pms_data.PM_SP_UG_2_5);
ESP_LOGI(TAG, "PM_SP_UG_10_0 %hu", pms_data.PM_SP_UG_10_0);
ESP_LOGI(TAG, "PM_AE_UG_1_0 %hu", pms_data.PM_AE_UG_1_0);
ESP_LOGI(TAG, "PM_AE_UG_2_5 %hu", pms_data.PM_AE_UG_2_5);
ESP_LOGI(TAG, "PM_AE_UG_10_0 %hu", pms_data.PM_AE_UG_10_0);
if (mqttConnected)
{
mqttVerbosePub(config::topic_pms_st_1_0.value(), std::to_string(pms_data.PM_SP_UG_1_0), 0, 1);
mqttVerbosePub(config::topic_pms_st_2_5.value(), std::to_string(pms_data.PM_SP_UG_2_5), 0, 1);
mqttVerbosePub(config::topic_pms_st_10_0.value(), std::to_string(pms_data.PM_SP_UG_10_0), 0, 1);
mqttVerbosePub(config::topic_pms_ae_1_0.value(), std::to_string(pms_data.PM_AE_UG_1_0), 0, 1);
mqttVerbosePub(config::topic_pms_ae_2_5.value(), std::to_string(pms_data.PM_AE_UG_2_5), 0, 1);
mqttVerbosePub(config::topic_pms_ae_10_0.value(), std::to_string(pms_data.PM_AE_UG_10_0), 0, 1);
}
}
pms_index = 0;
return;
}
else
{
pms_calculatedChecksum += ch;
uint8_t payloadIndex = pms_index - 4;
// Payload is common to all sensors (first 2x6 bytes).
if (payloadIndex < sizeof(pms_payload))
{
pms_payload[payloadIndex] = ch;
}
}
break;
}
pms_index++;
}
}
} // namespace deckenlampe

8
main/feature_pms.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
namespace deckenlampe {
void init_pms();
void update_pms();
} // namespace deckenlampe

View File

@ -29,6 +29,7 @@
#include "feature_dht.h"
#include "feature_tsl.h"
#include "feature_bmp.h"
#include "feature_pms.h"
#include "espchrono.h"
using namespace std::chrono_literals;
@ -108,6 +109,8 @@ extern "C" void app_main()
init_bmp();
init_pms();
while (true)
{
#if defined(CONFIG_ESP_TASK_WDT_PANIC) || defined(CONFIG_ESP_TASK_WDT)
@ -145,6 +148,9 @@ extern "C" void app_main()
update_bmp();
vPortYield();
update_pms();
vPortYield();
update_switch();
vPortYield();

View File

@ -63,6 +63,16 @@ ConfigWrapper<std::string> topic_bmp085_pressure{"topic_bmp085_pressure", "tpcbm
ConfigWrapper<std::string> topic_bmp085_temperature{"topic_bmp085_temperature", "tpcbmp085temper", "dahoam/wohnzimmer/bmp085_1/temperature"};
ConfigWrapper<std::string> topic_bmp085_altitude{"topic_bmp085_altitude", "tpcbmp085altitu", "dahoam/wohnzimmer/bmp085_1/altitude"};
ConfigWrapper<bool> enable_pms{"enable_pms", "enable_pms", false};
ConfigWrapper<gpio_num_t> pins_pms_rx{"pins_pms_rx", "pins_pms_rx", GPIO_NUM_25};
ConfigWrapper<gpio_num_t> pins_pms_tx{"pins_pms_tx", "pins_pms_tx", GPIO_NUM_26};
ConfigWrapper<std::string> topic_pms_st_1_0{"topic_pms_st_1_0", "tpcpmsst1_0", "dahoam/wohnzimmer/pms/st/1_0"};
ConfigWrapper<std::string> topic_pms_st_2_5{"topic_pms_st_2_5", "tpcpmsst2_5", "dahoam/wohnzimmer/pms/st/2_5"};
ConfigWrapper<std::string> topic_pms_st_10_0{"topic_pms_st_10_0", "tpcpmsst10_0", "dahoam/wohnzimmer/pms/st/10_0"};
ConfigWrapper<std::string> topic_pms_ae_1_0{"topic_pms_ae_1_0", "tpcpmsae1_0", "dahoam/wohnzimmer/pms/ae/1_0"};
ConfigWrapper<std::string> topic_pms_ae_2_5{"topic_pms_ae_2_5", "tpcpmsae2_5", "dahoam/wohnzimmer/pms/ae/2_5"};
ConfigWrapper<std::string> topic_pms_ae_10_0{"topic_pms_ae_10_0", "tpcpmsae10_0", "dahoam/wohnzimmer/pms/ae/10_0"};
ConfigWrapper<espchrono::seconds32> availableTimeoutTime{"availableTimeoutTime", "availTimeouTime", 1min};
ConfigWrapper<espchrono::seconds32> valueUpdateInterval{"valueUpdateInterval", "valUpdaInterval", 15s};
} // namespace config

View File

@ -68,6 +68,16 @@ extern ConfigWrapper<std::string> topic_bmp085_pressure;
extern ConfigWrapper<std::string> topic_bmp085_temperature;
extern ConfigWrapper<std::string> topic_bmp085_altitude;
extern ConfigWrapper<bool> enable_pms;
extern ConfigWrapper<gpio_num_t> pins_pms_rx;
extern ConfigWrapper<gpio_num_t> pins_pms_tx;
extern ConfigWrapper<std::string> topic_pms_st_1_0;
extern ConfigWrapper<std::string> topic_pms_st_2_5;
extern ConfigWrapper<std::string> topic_pms_st_10_0;
extern ConfigWrapper<std::string> topic_pms_ae_1_0;
extern ConfigWrapper<std::string> topic_pms_ae_2_5;
extern ConfigWrapper<std::string> topic_pms_ae_10_0;
extern ConfigWrapper<espchrono::seconds32> availableTimeoutTime;
extern ConfigWrapper<espchrono::seconds32> valueUpdateInterval;
@ -113,6 +123,15 @@ void foreachConfig(T &&callback)
callback(topic_bmp085_pressure);
callback(topic_bmp085_temperature);
callback(topic_bmp085_altitude);
callback(enable_pms);
callback(pins_pms_rx);
callback(pins_pms_tx);
callback(topic_pms_st_1_0);
callback(topic_pms_st_2_5);
callback(topic_pms_st_10_0);
callback(topic_pms_ae_1_0);
callback(topic_pms_ae_2_5);
callback(topic_pms_ae_10_0);
callback(availableTimeoutTime);
callback(valueUpdateInterval);
}

View File

@ -156,6 +156,19 @@ CONFIG_ARDUINO_SELECTIVE_COMPILATION=y
CONFIG_ARDUINO_SELECTIVE_Wire=y
# end of Arduino Configuration
#
# ESP Config lib settings
#
# CONFIG_LOG_LOCAL_LEVEL_CONFIG_NONE is not set
# CONFIG_LOG_LOCAL_LEVEL_CONFIG_ERROR is not set
# CONFIG_LOG_LOCAL_LEVEL_CONFIG_WARN is not set
CONFIG_LOG_LOCAL_LEVEL_CONFIG_INFO=y
# CONFIG_LOG_LOCAL_LEVEL_CONFIG_DEBUG is not set
# CONFIG_LOG_LOCAL_LEVEL_CONFIG_VERBOSE is not set
CONFIG_LOG_LOCAL_LEVEL_CONFIG=3
# CONFIG_SEPARATE_FACTORY_NVS_PARTITION is not set
# end of ESP Config lib settings
#
# espcpputils settings
#