#include #include void test_telemetry_serialization() { JsonDocument doc; JsonObject root = doc.to(); root["ts"] = 1716000000; root["dev"] = "ACV-TEST01"; JsonObject v = root["v"].to(); v["a"] = 230.1; v["b"] = 231.4; v["c"] = 229.8; JsonObject i = root["i"].to(); i["a"] = 15.2; i["b"] = 14.8; i["c"] = 15.5; JsonObject p = root["p"].to(); p["act"] = 10.5; p["react"] = 2.1; p["app"] = 10.7; root["f"] = 50.01; String output; serializeJson(doc, output); TEST_ASSERT_TRUE(output.length() > 0); TEST_ASSERT_TRUE(output.indexOf("ACV-TEST01") >= 0); TEST_ASSERT_TRUE(output.indexOf("230.1") >= 0); } void test_telemetry_deserialization() { const char* json = R"({"ts":1716000000,"dev":"ACV-TEST01","v":{"a":230.1,"b":231.4,"c":229.8},"f":50.01})"; JsonDocument doc; DeserializationError err = deserializeJson(doc, json); TEST_ASSERT_EQUAL(DeserializationError::Ok, err); TEST_ASSERT_EQUAL(1716000000, doc["ts"].as()); TEST_ASSERT_EQUAL_STRING("ACV-TEST01", doc["dev"].as()); TEST_ASSERT_FLOAT_WITHIN(0.01, 230.1, doc["v"]["a"].as()); TEST_ASSERT_FLOAT_WITHIN(0.01, 50.01, doc["f"].as()); } void test_command_parsing() { const char* json = R"({"cmd":"wifi_set","request_id":"cmd-abc123","params":{"ssid":"TestNet","password":"secret"}})"; JsonDocument doc; DeserializationError err = deserializeJson(doc, json); TEST_ASSERT_EQUAL(DeserializationError::Ok, err); TEST_ASSERT_EQUAL_STRING("wifi_set", doc["cmd"].as()); TEST_ASSERT_EQUAL_STRING("cmd-abc123", doc["request_id"].as()); TEST_ASSERT_EQUAL_STRING("TestNet", doc["params"]["ssid"].as()); } void test_heartbeat_serialization() { JsonDocument doc; JsonObject root = doc.to(); root["ts"] = 1716000000; root["dev"] = "ACV-TEST01"; root["fw"] = "1.0.0"; root["up"] = 86400; root["boot"] = 5; root["hb"] = 100; JsonObject health = root["health"].to(); health["heap_free"] = 120000; health["heap_min"] = 80000; JsonObject modbus = root["modbus"].to(); modbus["connected"] = true; modbus["success"] = 1000; modbus["errors"] = 2; String output; serializeJson(doc, output); TEST_ASSERT_TRUE(output.indexOf("\"boot\":5") >= 0); TEST_ASSERT_TRUE(output.indexOf("\"heap_free\":120000") >= 0); } void test_alert_serialization() { JsonDocument doc; JsonObject root = doc.to(); root["alert"] = "overvoltage"; root["severity"] = "warning"; root["message"] = "Phase A voltage 265.3V exceeds threshold 260.0V"; root["phase"] = "a"; root["value"] = 265.3; root["threshold"] = 260.0; String output; serializeJson(doc, output); TEST_ASSERT_TRUE(output.indexOf("overvoltage") >= 0); TEST_ASSERT_TRUE(output.indexOf("265.3") >= 0); } void test_registration_payload() { JsonDocument doc; JsonObject root = doc.to(); root["device_id"] = "ACV-AABBCCDDEEFF"; root["mac"] = "AA:BB:CC:DD:EE:FF"; root["firmware"] = "1.0.0"; root["hardware"] = "TTGO T-Call v1.4"; JsonArray caps = root["capabilities"].to(); caps.add("modbus"); caps.add("wifi"); caps.add("gsm"); caps.add("sd"); caps.add("ota"); String output; serializeJson(doc, output); TEST_ASSERT_TRUE(output.indexOf("ACV-AABBCCDDEEFF") >= 0); TEST_ASSERT_TRUE(output.indexOf("\"modbus\"") >= 0); } void test_empty_json_handling() { JsonDocument doc; DeserializationError err = deserializeJson(doc, "{}"); TEST_ASSERT_EQUAL(DeserializationError::Ok, err); TEST_ASSERT_TRUE(doc["missing"].isNull()); } void test_invalid_json_handling() { JsonDocument doc; DeserializationError err = deserializeJson(doc, "not json"); TEST_ASSERT_NOT_EQUAL(DeserializationError::Ok, err); } void setup() { delay(2000); UNITY_BEGIN(); RUN_TEST(test_telemetry_serialization); RUN_TEST(test_telemetry_deserialization); RUN_TEST(test_command_parsing); RUN_TEST(test_heartbeat_serialization); RUN_TEST(test_alert_serialization); RUN_TEST(test_registration_payload); RUN_TEST(test_empty_json_handling); RUN_TEST(test_invalid_json_handling); UNITY_END(); } void loop() {}