diff --git a/openBeken_win32_mvsc2017.vcxproj b/openBeken_win32_mvsc2017.vcxproj
index de06878fa..a75fd973e 100644
--- a/openBeken_win32_mvsc2017.vcxproj
+++ b/openBeken_win32_mvsc2017.vcxproj
@@ -948,6 +948,7 @@
true
+
diff --git a/openBeken_win32_mvsc2017.vcxproj.filters b/openBeken_win32_mvsc2017.vcxproj.filters
index 5c44ec298..aafa7ae68 100644
--- a/openBeken_win32_mvsc2017.vcxproj.filters
+++ b/openBeken_win32_mvsc2017.vcxproj.filters
@@ -866,6 +866,9 @@
SelfTest
+
+ SelfTest
+
diff --git a/src/driver/drv_battery.c b/src/driver/drv_battery.c
index c8c06d7aa..af0206341 100644
--- a/src/driver/drv_battery.c
+++ b/src/driver/drv_battery.c
@@ -22,12 +22,15 @@ static void Batt_Measure() {
float batt_ref, batt_res, vref;
ADDLOG_INFO(LOG_FEATURE_DRV, "DRV_BATTERY : Measure Battery volt en perc");
g_pin_adc = PIN_FindPinIndexForRole(IOR_BAT_ADC, g_pin_adc);
- if (PIN_FindPinIndexForRole(IOR_BAT_Relay, -1) == -1) {
+ if (PIN_FindPinIndexForRole(IOR_BAT_Relay, -1) == -1 && PIN_FindPinIndexForRole(IOR_BAT_Relay_n, -1) == -1) {
g_vdivider = 1;
}
// if divider equal to 1 then no need for relay activation
if (g_vdivider > 1) {
- g_pin_rel = PIN_FindPinIndexForRole(IOR_BAT_Relay, g_pin_rel);
+ g_pin_rel = PIN_FindPinIndexForRole(IOR_BAT_Relay, -1);
+ if (g_pin_rel == -1) {
+ g_pin_rel = PIN_FindPinIndexForRole(IOR_BAT_Relay_n, -1);
+ }
channel_rel = g_cfg.pins.channels[g_pin_rel];
}
HAL_ADC_Init(g_pin_adc);
@@ -65,6 +68,9 @@ static void Batt_Measure() {
g_lastbattvoltage = (int)g_battvoltage;
ADDLOG_INFO(LOG_FEATURE_DRV, "DRV_BATTERY : battery voltage : %f and percentage %f%%", g_battvoltage, g_battlevel);
}
+void Simulator_Force_Batt_Measure() {
+ Batt_Measure();
+}
int Battery_lastreading(int type)
{
diff --git a/src/driver/drv_battery.h b/src/driver/drv_battery.h
index 7542d7290..033b9fb58 100644
--- a/src/driver/drv_battery.h
+++ b/src/driver/drv_battery.h
@@ -1,6 +1,6 @@
// battery public void
-int Battery_lastreading();
+int Battery_lastreading(int type);
// read last value of battery driver value
enum {
diff --git a/src/hal/win32/hal_pins_win32.c b/src/hal/win32/hal_pins_win32.c
index 3d0cf0475..49d52fc80 100644
--- a/src/hal/win32/hal_pins_win32.c
+++ b/src/hal/win32/hal_pins_win32.c
@@ -80,6 +80,9 @@ bool SIM_IsPinADC(int index) {
return true;
return false;
}
+void SIM_SetIntegerValueADCPin(int index, int v) {
+ g_simulatedADCValues[index] = v;
+}
void SIM_SetVoltageOnADCPin(int index, float v) {
if (g_pinModes[index] != SIM_PIN_ADC)
return;
@@ -90,7 +93,7 @@ void SIM_SetVoltageOnADCPin(int index, float v) {
v = 0;
float f = v / 3.3f;
int iVal = f * 1024;
- g_simulatedADCValues[index] = iVal;
+ SIM_SetIntegerValueADCPin(index, v);
}
int SIM_GetPWMValue(int index) {
return g_simulatedPWMs[index];
diff --git a/src/httpserver/hass.c b/src/httpserver/hass.c
index 2bc402dcc..05ff770cc 100644
--- a/src/httpserver/hass.c
+++ b/src/httpserver/hass.c
@@ -67,6 +67,9 @@ void hass_populate_unique_id(ENTITY_TYPE type, int index, char* uniq_id) {
case CO2_SENSOR:
sprintf(uniq_id, "%s_%s_%d", longDeviceName, "co2", index);
break;
+ case SMOKE_SENSOR:
+ sprintf(uniq_id, "%s_%s_%d", longDeviceName, "smoke", index);
+ break;
case TVOC_SENSOR:
sprintf(uniq_id, "%s_%s_%d", longDeviceName, "tvoc", index);
break;
@@ -116,6 +119,7 @@ void hass_populate_device_config_channel(ENTITY_TYPE type, char* uniq_id, HassDe
case BINARY_SENSOR:
sprintf(info->channel, "binary_sensor/%s/config", uniq_id);
break;
+ case SMOKE_SENSOR:
case CO2_SENSOR:
case TVOC_SENSOR:
case POWER_SENSOR:
@@ -212,6 +216,10 @@ HassDeviceInfo* hass_init_device_info(ENTITY_TYPE type, int index, char* payload
isSensor = true;
sprintf(g_hassBuffer, "%s CO2", CFG_GetShortDeviceName());
break;
+ case SMOKE_SENSOR:
+ isSensor = true;
+ sprintf(g_hassBuffer, "%s Smoke", CFG_GetShortDeviceName());
+ break;
case TVOC_SENSOR:
isSensor = true;
sprintf(g_hassBuffer, "%s Tvoc", CFG_GetShortDeviceName());
@@ -472,6 +480,13 @@ HassDeviceInfo* hass_init_sensor_device_info(ENTITY_TYPE type, int channel, int
sprintf(g_hassBuffer, "~/%d/get", channel);
cJSON_AddStringToObject(info->root, "stat_t", g_hassBuffer);
break;
+ case SMOKE_SENSOR:
+ // there is no "smoke" class!
+ //cJSON_AddStringToObject(info->root, "dev_cla", "smoke");
+ cJSON_AddStringToObject(info->root, "unit_of_meas", "%");
+ sprintf(g_hassBuffer, "~/%d/get", channel);
+ cJSON_AddStringToObject(info->root, "stat_t", g_hassBuffer);
+ break;
case CO2_SENSOR:
cJSON_AddStringToObject(info->root, "dev_cla", "carbon_dioxide");
cJSON_AddStringToObject(info->root, "unit_of_meas", "ppm");
diff --git a/src/httpserver/hass.h b/src/httpserver/hass.h
index df23bac80..f6fc1a345 100644
--- a/src/httpserver/hass.h
+++ b/src/httpserver/hass.h
@@ -58,6 +58,8 @@ typedef enum {
/// @brief
CUSTOM_SENSOR,
/// @brief
+ SMOKE_SENSOR,
+ /// @brief
READONLYLOWMIDHIGH_SENSOR,
} ENTITY_TYPE;
diff --git a/src/httpserver/http_fns.c b/src/httpserver/http_fns.c
index dbc1ed511..21dee98f2 100644
--- a/src/httpserver/http_fns.c
+++ b/src/httpserver/http_fns.c
@@ -1825,6 +1825,15 @@ void doHomeAssistantDiscovery(const char* topic, http_request_t* request) {
discoveryQueued = true;
}
break;
+ case ChType_SmokePercent:
+ {
+ dev_info = hass_init_sensor_device_info(SMOKE_SENSOR, i, -1, -1);
+ MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN);
+ hass_free_device_info(dev_info);
+
+ discoveryQueued = true;
+ }
+ break;
case ChType_ReadOnly:
{
dev_info = hass_init_sensor_device_info(CUSTOM_SENSOR, i, -1, -1);
diff --git a/src/httpserver/new_http.c b/src/httpserver/new_http.c
index 1a94a072d..c5b91a5b4 100644
--- a/src/httpserver/new_http.c
+++ b/src/httpserver/new_http.c
@@ -458,7 +458,7 @@ const char* htmlPinRoleNames[] = {
"TM1638_CLK",
"TM1638_DAT",
"TM1638_STB",
- "error",
+ "BAT_Relay_n",
"error",
"error",
};
diff --git a/src/new_pins.c b/src/new_pins.c
index c39bc9347..238821bfe 100644
--- a/src/new_pins.c
+++ b/src/new_pins.c
@@ -544,6 +544,7 @@ void CHANNEL_SetAll(int iVal, int iFlags) {
case IOR_LED:
case IOR_LED_n:
case IOR_BAT_Relay:
+ case IOR_BAT_Relay_n:
case IOR_Relay:
case IOR_Relay_n:
CHANNEL_Set(g_cfg.pins.channels[i], iVal, iFlags);
@@ -657,6 +658,7 @@ void PIN_SetPinRoleForPinIndex(int index, int role) {
case IOR_LED:
case IOR_LED_n:
case IOR_BAT_Relay:
+ case IOR_BAT_Relay_n:
case IOR_Relay:
case IOR_Relay_n:
case IOR_LED_WIFI:
@@ -795,6 +797,7 @@ void PIN_SetPinRoleForPinIndex(int index, int role) {
case IOR_LED:
case IOR_LED_n:
case IOR_BAT_Relay:
+ case IOR_BAT_Relay_n:
case IOR_Relay:
case IOR_Relay_n:
{
@@ -805,7 +808,7 @@ void PIN_SetPinRoleForPinIndex(int index, int role) {
channelValue = g_channelValues[channelIndex];
HAL_PIN_Setup_Output(index);
- if (role == IOR_LED_n || role == IOR_Relay_n) {
+ if (role == IOR_LED_n || role == IOR_Relay_n || role == IOR_BAT_Relay_n) {
HAL_PIN_SetOutputValue(index, !channelValue);
}
else {
@@ -932,7 +935,7 @@ static void Channel_OnChanged(int ch, int prevValue, int iFlags) {
if (g_cfg.pins.roles[i] == IOR_Relay || g_cfg.pins.roles[i] == IOR_BAT_Relay || g_cfg.pins.roles[i] == IOR_LED) {
RAW_SetPinValue(i, bOn);
}
- else if (g_cfg.pins.roles[i] == IOR_Relay_n || g_cfg.pins.roles[i] == IOR_LED_n) {
+ else if (g_cfg.pins.roles[i] == IOR_Relay_n || g_cfg.pins.roles[i] == IOR_LED_n || g_cfg.pins.roles[i] == IOR_BAT_Relay_n) {
RAW_SetPinValue(i, !bOn);
}
else if (g_cfg.pins.roles[i] == IOR_PWM) {
@@ -1310,7 +1313,7 @@ bool CHANNEL_ShouldBePublished(int ch) {
if (g_cfg.pins.channels[i] == ch) {
if (role == IOR_Relay || role == IOR_Relay_n
|| role == IOR_LED || role == IOR_LED_n
- || role == IOR_ADC || role == IOR_BAT_ADC || role == IOR_BAT_Relay
+ || role == IOR_ADC || role == IOR_BAT_ADC
|| role == IOR_CHT8305_DAT || role == IOR_SHT3X_DAT || role == IOR_SGP_DAT
|| role == IOR_DigitalInput || role == IOR_DigitalInput_n
|| role == IOR_DoorSensorWithDeepSleep || role == IOR_DoorSensorWithDeepSleep_NoPup
@@ -1351,6 +1354,7 @@ int CHANNEL_GetRoleForOutputChannel(int ch) {
if (g_cfg.pins.channels[i] == ch) {
switch (g_cfg.pins.roles[i]) {
case IOR_BAT_Relay:
+ case IOR_BAT_Relay_n:
case IOR_Relay:
case IOR_Relay_n:
case IOR_LED:
@@ -1790,7 +1794,7 @@ const char* g_channelTypeNames[] = {
"Custom",
"Power_div10",
"ReadOnlyLowMidHigh",
- "error",
+ "SmokePercent",
"error",
"error",
"error",
@@ -1917,7 +1921,6 @@ void PIN_get_Relay_PWM_Count(int* relayCount, int* pwmCount, int* dInputCount) {
for (i = 0; i < PLATFORM_GPIO_MAX; i++) {
int role = PIN_GetPinRoleForPinIndex(i);
switch (role) {
- case IOR_BAT_Relay:
case IOR_Relay:
case IOR_Relay_n:
case IOR_LED:
@@ -1983,7 +1986,7 @@ int h_isChannelRelay(int tg_ch) {
if (tg_ch != ch)
continue;
role = PIN_GetPinRoleForPinIndex(i);
- if (role == IOR_BAT_Relay || role == IOR_Relay || role == IOR_Relay_n || role == IOR_LED || role == IOR_LED_n) {
+ if (role == IOR_Relay || role == IOR_Relay_n || role == IOR_LED || role == IOR_LED_n) {
return true;
}
if ((role == IOR_BridgeForward) || (role == IOR_BridgeReverse))
diff --git a/src/new_pins.h b/src/new_pins.h
index 64e53bab1..b733cc29a 100644
--- a/src/new_pins.h
+++ b/src/new_pins.h
@@ -530,12 +530,20 @@ typedef enum ioRole_e {
//iodetail:"file":"new_pins.h",
//iodetail:"driver":""}
IOR_TM1638_STB,
+ //iodetail:{"name":"BAT_Relay_n",
+ //iodetail:"title":"TODO",
+ //iodetail:"descr":"Like BAT_Relay, but inversed. See [battery driver topic here](https://www.elektroda.com/rtvforum/topic3959103.html)",
+ //iodetail:"enum":"IOR_BAT_Relay_n",
+ //iodetail:"file":"new_pins.h",
+ //iodetail:"driver":""}
+ IOR_BAT_Relay_n,
//iodetail:{"name":"Total_Options",
//iodetail:"title":"TODO",
//iodetail:"descr":"Current total number of available IOR roles",
//iodetail:"enum":"IOR_Total_Options",
//iodetail:"file":"new_pins.h",
//iodetail:"driver":""}
+
IOR_Total_Options,
} ioRole_t;
@@ -803,6 +811,14 @@ typedef enum channelType_e {
//chandetail:"file":"new_pins.h",
//chandetail:"driver":""}
ChType_ReadOnlyLowMidHigh,
+ //chandetail:{"name":"SmokePercent",
+ //chandetail:"title":"TODO",
+ //chandetail:"descr":"Smoke percentage",
+ //chandetail:"enum":"ChType_SmokePercent",
+ //chandetail:"file":"new_pins.h",
+ //chandetail:"driver":""}
+ ChType_SmokePercent,
+
//chandetail:{"name":"Max",
//chandetail:"title":"TODO",
//chandetail:"descr":"This is the current total number of available channel types.",
diff --git a/src/selftest/selftest_batteryDriver.c b/src/selftest/selftest_batteryDriver.c
new file mode 100644
index 000000000..60ad6d7d4
--- /dev/null
+++ b/src/selftest/selftest_batteryDriver.c
@@ -0,0 +1,50 @@
+#ifdef WINDOWS
+
+#include "selftest_local.h"
+#include "../driver/drv_battery.h"
+
+// P23 is ADC, it is connected to two resistors, both 1k,
+// one is connected to P26, second to VDD
+void Test_Battery_SmokeSensor() {
+ // reset whole device
+ SIM_ClearOBK(0);
+
+ PIN_SetPinRoleForPinIndex(26, IOR_BAT_Relay_n);
+ // some random unused channel
+ PIN_SetPinChannelForPinIndex(26, 5);
+
+ PIN_SetPinRoleForPinIndex(23, IOR_BAT_ADC);
+ PIN_SetPinChannelForPinIndex(23, 5);
+
+ CMD_ExecuteCommand("startDriver Battery", 0);
+ // Battery 1.997V - raw ADC 1714
+ // Battery 2.998V - raw ADC 2588
+ // args minbatt and maxbatt in mv. optional V_divider(2), Vref(default 2400) and ADC bits(4096)
+ CMD_ExecuteCommand("Battery_Setup 2000 3000 2 2400 4096", 0);
+
+ // Battery 2.998V - raw ADC 2588 - 100%
+ SIM_SetIntegerValueADCPin(23, 2588);
+
+ Simulator_Force_Batt_Measure();
+
+ // assert: current ,expected, max difference, the voltage is in mV
+ SELFTEST_ASSERT_FLOATCOMPAREEPSILON(Battery_lastreading(OBK_BATT_VOLTAGE), 2998, 100);
+ // assert: current ,expected, max difference
+ SELFTEST_ASSERT_FLOATCOMPAREEPSILON(Battery_lastreading(OBK_BATT_LEVEL), 100, 5.0f);
+
+ // Battery 1.997V - raw ADC 1714 - 0%
+ SIM_SetIntegerValueADCPin(23, 1714);
+
+ Simulator_Force_Batt_Measure();
+
+ // assert: current ,expected, max difference, the voltage is in mV
+ SELFTEST_ASSERT_FLOATCOMPAREEPSILON(Battery_lastreading(OBK_BATT_VOLTAGE), 1997, 100);
+ // assert: current ,expected, max difference
+ SELFTEST_ASSERT_FLOATCOMPAREEPSILON(Battery_lastreading(OBK_BATT_LEVEL), 0, 5.0f);
+}
+void Test_Battery() {
+ Test_Battery_SmokeSensor();
+
+}
+
+#endif
diff --git a/src/selftest/selftest_local.h b/src/selftest/selftest_local.h
index f1baba9d4..e99f11751 100644
--- a/src/selftest/selftest_local.h
+++ b/src/selftest/selftest_local.h
@@ -14,6 +14,7 @@ void SelfTest_Failed(const char *file, const char *function, int line, const cha
SelfTest_Failed(__FILE__, __FUNCTION__, __LINE__, #expr)
#define SELFTEST_ASSERT_FLOATCOMPARE(exp, res) SELFTEST_ASSERT(Float_Equals(exp, res));
+#define SELFTEST_ASSERT_FLOATCOMPAREEPSILON(exp, res, eps) SELFTEST_ASSERT(Float_EqualsEpsilon(exp, res, eps));
#define SELFTEST_ASSERT_EXPRESSION(exp, res) SELFTEST_ASSERT(Float_Equals(CMD_EvaluateExpression(exp,0), res));
#define SELFTEST_ASSERT_CHANNEL(channelIndex, res) SELFTEST_ASSERT(Float_Equals(CHANNEL_Get(channelIndex), res));
#define SELFTEST_ASSERT_CHANNELTYPE(channelIndex, res) SELFTEST_ASSERT(CHANNEL_GetType(channelIndex)==res);
@@ -43,6 +44,10 @@ inline bool Float_Equals(float a, float b) {
float res = fabs(a - b);
return res < 0.001f;
}
+inline bool Float_EqualsEpsilon(float a, float b, float epsilon) {
+ float res = fabs(a - b);
+ return res < epsilon;
+}
#define VA_BUFFER_SIZE 4096
#define VA_COUNT 4
@@ -62,7 +67,7 @@ inline const char *va(const char *fmt, ...) {
return p;
}
-
+void Test_Battery();
void Test_Flash_Search();
void Test_JSON_Lib();
void Test_Commands_Startup();
diff --git a/src/sim/sim_import.h b/src/sim/sim_import.h
index ef1ba5c9b..e85fec945 100644
--- a/src/sim/sim_import.h
+++ b/src/sim/sim_import.h
@@ -9,6 +9,7 @@ extern "C" {
bool SIM_IsPinPWM(int index);
bool SIM_IsPinADC(int index);
void SIM_SetVoltageOnADCPin(int index, float v);
+ void SIM_SetIntegerValueADCPin(int index, int v);
int SIM_GetPWMValue(int index);
// flash control simulation
void SIM_SetupFlashFileReading(const char *flashPath);
diff --git a/src/win_main.c b/src/win_main.c
index 3a303437b..3fe10048e 100644
--- a/src/win_main.c
+++ b/src/win_main.c
@@ -127,6 +127,8 @@ void SIM_ClearOBK(const char *flashPath) {
Main_Init();
}
void Win_DoUnitTests() {
+
+ Test_Battery();
Test_TuyaMCU_BatteryPowered();
Test_JSON_Lib();
Test_MQTT_Get_LED_EnableAll();