diff --git a/.drone.yml b/.drone.yml index 8fe9ac6..293b48f 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,24 +1,38 @@ --- kind: pipeline type: exec -name: upload gateway firmare +name: gateway pipeline platform: os: linux arch: arm steps: -- name: upload +- name: native tests + commands: + - cd gateway + - pio test -e native + +- name: embedded tests + commands: + - cd gateway + - LD_LIBRARY_PATH=~/.platformio/packages/tool-simavr/lib/ pio test -e embedded --without-uploading + +- name: upload firmware commands: - cd gateway - service ser2net stop - pio run -e pro-mini - echo -n 'reset' > /dev/ttyUSB0; sleep 1s; avrdude -patmega328p -carduino -P/dev/ttyUSB0 -b115200 -D -Uflash:w:.pio/build/pro-mini/firmware.hex:i -v - service ser2net start + when: + branch: + - gateway trigger: branch: - gateway + - gw/* node: host: homebox diff --git a/gateway/include/Protocol_1.h b/gateway/include/Protocol_1.h index ee77167..f05e7f8 100644 --- a/gateway/include/Protocol_1.h +++ b/gateway/include/Protocol_1.h @@ -1,9 +1,6 @@ #pragma once #include "Protocol.h" - -#define RC_STATE(value) value & 0x1 -#define RC_DEVICE(value) (value >> 1) & 0x1F -#define RC_GROUP(value) (value >> 6) & 0x1F +#include "RcDecoder.h" class Protocol_1 : public Protocol { @@ -22,48 +19,11 @@ public: void toJson(unsigned long value, JsonDocument& jsonDoc) override { JsonObject rcSwitch = jsonDoc.createNestedObject("rcSwitch"); rcSwitch["protocol"] = protocol; - Decoder decoder; + RcDecoder decoder; decoder.decode(value); rcSwitch["state"] = decoder.state; rcSwitch["group"] = String(decoder.group, BIN); rcSwitch["channel"] = decoder.device; rcSwitch["raw_value"] = value; } - -private: - struct Decoder { - bool state; - char group; - byte device; - - void decode(unsigned long value) { - value = value >> 2; - unsigned long res = 0; - for (int i = 0; i < 12; i++) { - res |= ((value & 1) ^ 1) << i; - value = value >> 2; - } - - state = RC_STATE(res); - group = RC_GROUP(res); - switch (RC_DEVICE(res)) { - case 0b10000: - device = 1; - break; - case 0b01000: - device = 2; - break; - case 0b00100: - device = 3; - break; - case 0b00010: - device = 4; - break; - case 0b00001: - device = 5; - break; - } - } - }; }; - diff --git a/gateway/include/Protocol_2.h b/gateway/include/Protocol_2.h index 0e32a85..589154e 100644 --- a/gateway/include/Protocol_2.h +++ b/gateway/include/Protocol_2.h @@ -1,6 +1,6 @@ #pragma once #include "Protocol.h" -#include "Tiny.h" +#include "TinyComponent.h" class Protocol_2 : public Protocol { @@ -33,35 +33,4 @@ public: } } -private: - bool buildSensorJson(unsigned long value, JsonDocument& jsonDoc) { - JsonObject sensor = jsonDoc.createNestedObject("sensor"); - sensor["id"] = ID(value); - - float voltage = (float)GET_VCC(value) / 1000; - if (voltage != 0) { - JsonObject diagnostic = sensor.createNestedObject("diagnostic"); - diagnostic["voltage"] = voltage; - } - - switch (GET_TYPE(value)) { - case SensorType::GENERIC: - sensor["value"] = GET_VALUE(value); - break; - case SensorType::TEMPERATURE: - sensor["temperature"] = (float)GET_TEMP(value) / 10; - break; - case SensorType::HUMIDITY: - sensor["humidity"] = (float)GET_HUMIDITY(value) / 10; - break; - case SensorType::CONTACT: - sensor["state"] = GET_STATE(value) ? "on" : "off"; - break; - default: - return false; - } - - return true; - } - }; \ No newline at end of file diff --git a/gateway/include/RcDecoder.h b/gateway/include/RcDecoder.h new file mode 100644 index 0000000..e43e564 --- /dev/null +++ b/gateway/include/RcDecoder.h @@ -0,0 +1,38 @@ +#define RC_STATE(value) value & 0x1 +#define RC_DEVICE(value) (value >> 1) & 0x1F +#define RC_GROUP(value) (value >> 6) & 0x1F + +struct RcDecoder { + bool state; + char group; + unsigned char device; + + void decode(unsigned long value) { + value = value >> 2; + unsigned long res = 0; + for (int i = 0; i < 12; i++) { + res |= ((value & 1) ^ 1) << i; + value = value >> 2; + } + + state = RC_STATE(res); + group = RC_GROUP(res); + switch (RC_DEVICE(res)) { + case 0b10000: + device = 1; + break; + case 0b01000: + device = 2; + break; + case 0b00100: + device = 3; + break; + case 0b00010: + device = 4; + break; + case 0b00001: + device = 5; + break; + } + } +}; diff --git a/gateway/include/TinyComponent.h b/gateway/include/TinyComponent.h new file mode 100644 index 0000000..beb5c12 --- /dev/null +++ b/gateway/include/TinyComponent.h @@ -0,0 +1,32 @@ +#include +#include "Tiny.h" + +bool buildSensorJson(unsigned long value, JsonDocument& jsonDoc) { + JsonObject sensor = jsonDoc.createNestedObject("sensor"); + sensor["id"] = ID(value); + + float voltage = (float)GET_VCC(value) / 1000; + if (voltage != 0) { + JsonObject diagnostic = sensor.createNestedObject("diagnostic"); + diagnostic["voltage"] = voltage; + } + + switch (GET_TYPE(value)) { + case SensorType::GENERIC: + sensor["value"] = GET_VALUE(value); + break; + case SensorType::TEMPERATURE: + sensor["temperature"] = (float)GET_TEMP(value) / 10; + break; + case SensorType::HUMIDITY: + sensor["humidity"] = (float)GET_HUMIDITY(value) / 10; + break; + case SensorType::CONTACT: + sensor["state"] = GET_STATE(value) ? "on" : "off"; + break; + default: + return false; + } + + return true; +} diff --git a/gateway/platformio.ini b/gateway/platformio.ini index 5d8e537..7c9ead9 100644 --- a/gateway/platformio.ini +++ b/gateway/platformio.ini @@ -21,3 +21,29 @@ lib_deps = adafruit/DHT sensor library@1.3.10 build_flags = -D DHT_SENSOR=0 upload_port = /dev/ttyUSB0 + +[env:native] +platform = native +test_filter = test_native + +[env:embedded] +platform = atmelavr +framework = arduino +board = miniatmega328 +lib_extra_dirs = + ../libraries +lib_deps = + sui77/rc-switch@^2.6.3 + bblanchon/ArduinoJson@6.16.1 + +platform_packages = + platformio/tool-simavr +test_speed = 9600 +test_testing_command = + ${platformio.packages_dir}/tool-simavr/bin/simavr + -m + atmega328p + -f + 16000000L + ${platformio.build_dir}/${this.__env__}/firmware.elf +test_filter = test_embedded diff --git a/gateway/test/test_embedded/sensor_builder.cpp b/gateway/test/test_embedded/sensor_builder.cpp new file mode 100644 index 0000000..8ca3ca3 --- /dev/null +++ b/gateway/test/test_embedded/sensor_builder.cpp @@ -0,0 +1,116 @@ +#include +#include +#include "TinyComponent.h" + +void setUp(void) { + // set stuff up here +} + +void tearDown(void) { + // clean stuff up here +} + +void test_unknown_sensor_type(void) { + StaticJsonDocument<200> jsonDoc; + unsigned long value = TYPE(0); + TEST_ASSERT_EQUAL(false, buildSensorJson(value, jsonDoc)); +} + +void test_max_temp(void) { + StaticJsonDocument<200> jsonDoc; + unsigned long value = TEMP(1023) | TYPE(SensorType::TEMPERATURE); + TEST_ASSERT_EQUAL(true, buildSensorJson(value, jsonDoc)); + + JsonObject sensor = jsonDoc["sensor"]; + TEST_ASSERT_EQUAL(102.3, sensor["temperature"]); +} + +void test_overflow_value(void) { + StaticJsonDocument<200> jsonDoc; + unsigned long value = VALUE(1024) | TYPE(SensorType::GENERIC); + TEST_ASSERT_EQUAL(true, buildSensorJson(value, jsonDoc)); + + JsonObject sensor = jsonDoc["sensor"]; + TEST_ASSERT_EQUAL(0, sensor["value"]); +} + +void test_max_voltage(void) { + StaticJsonDocument<200> jsonDoc; + unsigned long value = VCC(8191) | TYPE(SensorType::GENERIC); + TEST_ASSERT_EQUAL(true, buildSensorJson(value, jsonDoc)); + + JsonObject diagnostic = jsonDoc["sensor"]["diagnostic"]; + TEST_ASSERT_EQUAL(8.191, diagnostic["voltage"]); +} + +void test_overflow_voltage(void) { + StaticJsonDocument<200> jsonDoc; + unsigned long value = VCC(8192) | TYPE(SensorType::GENERIC); + TEST_ASSERT_EQUAL(true, buildSensorJson(value, jsonDoc)); + + JsonObject diagnostic = jsonDoc["sensor"]["diagnostic"]; + TEST_ASSERT_EQUAL(0, diagnostic["voltage"]); +} + +void test_temp_sensor(void) { + StaticJsonDocument<200> jsonDoc; + unsigned long value = ID(SensorId::TEMP_SENSOR) | TEMP(210) | TYPE(SensorType::TEMPERATURE); + TEST_ASSERT_EQUAL(true, buildSensorJson(value, jsonDoc)); + + JsonObject sensor = jsonDoc["sensor"]; + TEST_ASSERT_EQUAL(SensorId::TEMP_SENSOR, sensor["id"]); + TEST_ASSERT_EQUAL(21, sensor["temperature"]); +} + +void test_temp_sensor_with_voltage(void) { + StaticJsonDocument<200> jsonDoc; + unsigned long value = ID(SensorId::TEMP_SENSOR) | TEMP(320) | TYPE(SensorType::TEMPERATURE) | VCC(2847L); + TEST_ASSERT_EQUAL(true, buildSensorJson(value, jsonDoc)); + + JsonObject sensor = jsonDoc["sensor"]; + TEST_ASSERT_EQUAL(SensorId::TEMP_SENSOR, sensor["id"]); + TEST_ASSERT_EQUAL(32, sensor["temperature"]); + + JsonObject diagnostic = sensor["diagnostic"]; + TEST_ASSERT_EQUAL(2.847, diagnostic["voltage"]); +} + +void test_oil_sensor(void) { + StaticJsonDocument<200> jsonDoc; + unsigned long value = ID(SensorId::OIL_SENSOR) | VALUE(150) | TYPE(SensorType::GENERIC); + TEST_ASSERT_EQUAL(true, buildSensorJson(value, jsonDoc)); + + JsonObject sensor = jsonDoc["sensor"]; + TEST_ASSERT_EQUAL(SensorId::OIL_SENSOR, sensor["id"]); + TEST_ASSERT_EQUAL(150, sensor["value"]); +} + +void test_oil_sensor_with_voltage(void) { + StaticJsonDocument<200> jsonDoc; + unsigned long value = ID(SensorId::OIL_SENSOR) | TEMP(200) | TYPE(SensorType::GENERIC) | VCC(2847L); + TEST_ASSERT_EQUAL(true, buildSensorJson(value, jsonDoc)); + + JsonObject sensor = jsonDoc["sensor"]; + TEST_ASSERT_EQUAL(SensorId::OIL_SENSOR, sensor["id"]); + TEST_ASSERT_EQUAL(200, sensor["value"]); + + JsonObject diagnostic = sensor["diagnostic"]; + TEST_ASSERT_EQUAL(2.847, diagnostic["voltage"]); +} + +void setup() { + UNITY_BEGIN(); + RUN_TEST(test_unknown_sensor_type); + RUN_TEST(test_max_temp); + RUN_TEST(test_overflow_value); + RUN_TEST(test_max_voltage); + RUN_TEST(test_overflow_voltage); + RUN_TEST(test_temp_sensor); + RUN_TEST(test_temp_sensor_with_voltage); + RUN_TEST(test_oil_sensor); + RUN_TEST(test_oil_sensor_with_voltage); + UNITY_END(); +} + +void loop() { +} diff --git a/gateway/test/test_native/decoder.cpp b/gateway/test/test_native/decoder.cpp new file mode 100644 index 0000000..dea0636 --- /dev/null +++ b/gateway/test/test_native/decoder.cpp @@ -0,0 +1,35 @@ +#include +#include "RcDecoder.h" + +RcDecoder d; + +void setUp(void) { + // set stuff up here +} + +void tearDown(void) { + // clean stuff up here +} + +void test_1_2_on(void) { + d.decode(5574993); + TEST_ASSERT_EQUAL(true, d.state); + TEST_ASSERT_EQUAL(1, d.group); + TEST_ASSERT_EQUAL(2, d.device); +} + +void test_1_1_off(void) { + d.decode(5571924); + TEST_ASSERT_EQUAL(false, d.state); + TEST_ASSERT_EQUAL(1, d.group); + TEST_ASSERT_EQUAL(1, d.device); +} + +int main(int argc, char **argv) { + UNITY_BEGIN(); + RUN_TEST(test_1_2_on); + RUN_TEST(test_1_1_off); + UNITY_END(); + + return 0; +} diff --git a/libraries/Tiny/Tiny.h b/libraries/Tiny/Tiny.h index 5bfc8e0..653be12 100644 --- a/libraries/Tiny/Tiny.h +++ b/libraries/Tiny/Tiny.h @@ -1,28 +1,34 @@ #pragma once +#define MASK_ID 0x1F +#define MASK_VCC 0x1FFF +#define MASK_VALUE 0x3FF +#define MASK_STATE 0x1 +#define MASK_TYPE 0xF + #define ID(value) (value & 0x1F) -#define VCC(value) ((value & 0x1FFF) << 5) -#define TEMP(value) (((unsigned long)value & 0x2FF) << 18) -#define HUMIDITY(value) (((unsigned long)value & 0x2FF) << 18) -#define VALUE(value) (((unsigned long)value & 0x2FF) << 18) -#define STATE(value) ((value & 0x1) << 27) -#define TYPE(value) (((unsigned long)value & 0xF) << 28) +#define VCC(value) (((unsigned long)value & MASK_VCC) << 5) +#define TEMP(value) (((unsigned long)value & MASK_VALUE) << 18) +#define HUMIDITY(value) (((unsigned long)value & MASK_VALUE) << 18) +#define VALUE(value) (((unsigned long)value & MASK_VALUE) << 18) +#define STATE(value) ((value & MASK_STATE) << 27) +#define TYPE(value) (((unsigned long)value & MASK_TYPE) << 28) -#define GET_TYPE(value) (((unsigned long)value >> 28) & 0xF) -#define GET_STATE(value) ((value >> 27) & 0x1) -#define GET_TEMP(value) (((unsigned long)value >> 18) & 0x2FF) -#define GET_HUMIDITY(value) (((unsigned long)value >> 18) & 0x2FF) -#define GET_VALUE(value) (((unsigned long)value >> 18) & 0x2FF) -#define GET_VCC(value) (((unsigned long)value >> 5) & 0x1FFF) +#define GET_TYPE(value) (((unsigned long)value >> 28) & MASK_TYPE) +#define GET_STATE(value) ((value >> 27) & MASK_STATE) +#define GET_TEMP(value) (((unsigned long)value >> 18) & MASK_VALUE) +#define GET_HUMIDITY(value) (((unsigned long)value >> 18) & MASK_VALUE) +#define GET_VALUE(value) (((unsigned long)value >> 18) & MASK_VALUE) +#define GET_VCC(value) (((unsigned long)value >> 5) & MASK_VCC) -enum SensorType { +enum SensorType : unsigned short { GENERIC = 4, HUMIDITY = 5, TEMPERATURE = 6, CONTACT = 7 }; -enum SensorId : int { +enum SensorId : unsigned short { WINDOW1 = 1, WINDOW2 = 2, WATER_SENSOR = 3,