added feature_pms
This commit is contained in:
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -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
|
||||
|
1
components/ArduinoJson
Submodule
1
components/ArduinoJson
Submodule
Submodule components/ArduinoJson added at 475a650703
Submodule components/arduino-esp32 updated: b0223be116...c9ca6f199b
1
components/espconfiglib
Submodule
1
components/espconfiglib
Submodule
Submodule components/espconfiglib added at 8af9f032cc
Submodule components/espwifistack updated: dc31bacf98...a483ae1533
53
export.sh
53
export.sh
@ -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
|
||||
|
@ -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
196
main/feature_pms.cpp
Normal 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
8
main/feature_pms.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
namespace deckenlampe {
|
||||
|
||||
void init_pms();
|
||||
void update_pms();
|
||||
|
||||
} // namespace deckenlampe
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
13
sdkconfig
13
sdkconfig
@ -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
|
||||
#
|
||||
|
Reference in New Issue
Block a user