Add conversions for Home Assistant values: duration, time, own texts, auto unit

- Show as number (multiplier, decimals, auto unit W -> kW -> MW, without
  minus sign), duration (seconds/minutes/hours as 2h 21m, 2:21:00, 2:21 or
  smart), time (HA timestamps in local time, with weekday or date, or
  relative: over 34 min / 12 min geleden) or own texts per state.
- Page format 3; version 2 pages are converted. Version 2.7.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-15 21:50:19 +02:00
1 parent 93b9bec69a
commit 87e242bf89
11 files changed
+601 -30

No files matched your search

+133
View File
@@ -1739,6 +1739,135 @@ void test_selector_add_to_rotation()
TEST_ASSERT_EQUAL_STRING("3D printer", sel2.update(600, CHOSEN_PAGE_SECONDS * 1000).page);
}
// ---------------------------------------------------------------------------
// Home Assistant value conversions
// ---------------------------------------------------------------------------
static PageElement haElement(HaShow show, uint8_t format = 0)
{
PageElement e;
e.type = ElementType::HaValue;
strcpy(e.entity, "sensor.x");
e.show = show;
e.format = format;
return e;
}
void test_ha_auto_unit_and_absolute()
{
PageElement e = haElement(HaShow::Number);
e.auto_unit = true;
strcpy(e.suffix, " W");
TEST_ASSERT_EQUAL_STRING("1.3 kW", textOf(e, "1257").c_str());
TEST_ASSERT_EQUAL_STRING("950 W", textOf(e, "950").c_str());
TEST_ASSERT_EQUAL_STRING("-2.5 kW", textOf(e, "-2500").c_str());
e.absolute = true;
TEST_ASSERT_EQUAL_STRING("2.5 kW", textOf(e, "-2500").c_str());
strcpy(e.suffix, "Wh");
e.decimals = 2;
TEST_ASSERT_EQUAL_STRING("26.30kWh", textOf(e, "26300").c_str());
strcpy(e.suffix, "kWh");
e.decimals = DECIMALS_AS_IS;
TEST_ASSERT_EQUAL_STRING("18.6MWh", textOf(e, "18621.326").c_str());
TEST_ASSERT_EQUAL_STRING("500.0Wh", textOf(e, "0.5").c_str()); // below 1: smaller unit
strcpy(e.suffix, "%"); // not a unit it knows
TEST_ASSERT_EQUAL_STRING("37%", textOf(e, "37").c_str());
}
void test_ha_duration()
{
PageElement e = haElement(HaShow::Duration, DURATION_PARTS);
TEST_ASSERT_EQUAL_STRING("2h 20m", textOf(e, "8452.2").c_str());
TEST_ASSERT_EQUAL_STRING("1d 1h 1m", textOf(e, "90061").c_str());
TEST_ASSERT_EQUAL_STRING("2d", textOf(e, "172800").c_str());
TEST_ASSERT_EQUAL_STRING("45s", textOf(e, "45").c_str());
e.input_unit = UNIT_MINUTES;
TEST_ASSERT_EQUAL_STRING("1h 30m", textOf(e, "90").c_str());
e.input_unit = UNIT_HOURS;
e.format = DURATION_H_MM_SS;
TEST_ASSERT_EQUAL_STRING("26:30:00", textOf(e, "26.5").c_str());
e.format = DURATION_H_MM;
TEST_ASSERT_EQUAL_STRING("26:30", textOf(e, "26.5").c_str());
e.input_unit = UNIT_SECONDS;
e.format = DURATION_SMART;
TEST_ASSERT_EQUAL_STRING("2 uur", textOf(e, "8452").c_str());
TEST_ASSERT_EQUAL_STRING("1 dag", textOf(e, "90000").c_str());
TEST_ASSERT_EQUAL_STRING("34 min", textOf(e, "2040").c_str());
e.language = Language::English;
TEST_ASSERT_EQUAL_STRING("2 hours", textOf(e, "8452").c_str());
TEST_ASSERT_EQUAL_STRING("--", textOf(e, "unknown").c_str());
TEST_ASSERT_EQUAL_STRING("idle", textOf(e, "idle").c_str()); // not a number: as is
}
void test_ha_timestamps()
{
int64_t s = 0;
TEST_ASSERT_TRUE(parseTimestamp("2000-01-01T00:00:00+00:00", s));
TEST_ASSERT_EQUAL_INT64(0, s);
TEST_ASSERT_TRUE(parseTimestamp("2026-10-15T21:07:00+00:00", s));
int64_t a = s;
TEST_ASSERT_TRUE(parseTimestamp("2026-10-15T23:07:00+02:00", s));
TEST_ASSERT_EQUAL_INT64(a, s);
TEST_ASSERT_TRUE(parseTimestamp("2026-10-15T21:07:00.515369Z", s));
TEST_ASSERT_EQUAL_INT64(a, s);
TEST_ASSERT_TRUE(parseTimestamp("2026-10-15 21:07:00", s));
TEST_ASSERT_EQUAL_INT64(a, s);
TEST_ASSERT_FALSE(parseTimestamp("21:07", s));
TEST_ASSERT_FALSE(parseTimestamp("2026-10-15T21:07:00+0200x", s));
// textOf: Thursday 15 October 2026 08:05:00 local; CEST is UTC+2
PageElement e = haElement(HaShow::Time, TIMESTAMP_H_MM);
auto at = [&](const char *value) {
LocalTime t;
t.year = 2026;
t.month = 10;
t.day = 15;
t.weekday = 4;
t.hour = 8;
t.minute = 5;
t.utc_offset = 120;
char out[64];
ElementValues values;
values.ha_value = value;
elementText(e, t, values, out, sizeof(out));
return std::string(out);
};
TEST_ASSERT_EQUAL_STRING("23:07", at("2026-10-15T21:07:00+00:00").c_str());
e.format = TIMESTAMP_WEEKDAY_H_MM;
TEST_ASSERT_EQUAL_STRING("vr 01:30", at("2026-10-15T23:30:00+00:00").c_str()); // the next day
e.format = TIMESTAMP_DATE_H_MM;
TEST_ASSERT_EQUAL_STRING("16-10 01:30", at("2026-10-15T23:30:00+00:00").c_str());
e.format = TIMESTAMP_RELATIVE;
TEST_ASSERT_EQUAL_STRING("over 34 min", at("2026-10-15T06:39:00+00:00").c_str());
TEST_ASSERT_EQUAL_STRING("12 min geleden", at("2026-10-15T05:53:00+00:00").c_str());
TEST_ASSERT_EQUAL_STRING("nu", at("2026-10-15T06:05:30+00:00").c_str());
TEST_ASSERT_EQUAL_STRING("over 2 uur", at("2026-10-15T08:30:00+00:00").c_str());
e.language = Language::English;
TEST_ASSERT_EQUAL_STRING("3 days ago", at("2026-10-12T06:00:00+00:00").c_str());
TEST_ASSERT_EQUAL_STRING("soon", at("soon").c_str()); // not a timestamp: as is
}
void test_ha_text_map()
{
PageElement e = haElement(HaShow::Map);
strcpy(e.map, "printing=Bezig, standby = Klaar ,paused=Pauze,=leeg");
strcpy(e.text, "3D ");
TEST_ASSERT_EQUAL_STRING("3D Bezig", textOf(e, "printing").c_str());
TEST_ASSERT_EQUAL_STRING("3D Klaar", textOf(e, "Standby").c_str());
TEST_ASSERT_EQUAL_STRING("3D Pauze", textOf(e, "paused").c_str());
TEST_ASSERT_EQUAL_STRING("3D error", textOf(e, "error").c_str()); // not in the list: as is
TEST_ASSERT_EQUAL_STRING("3D --", textOf(e, "unavailable").c_str());
DynamicPage page;
page.element_count = 1;
page.elements[0] = e;
TEST_ASSERT_NULL(validatePage(page));
page.elements[0].show = HaShow::Count;
TEST_ASSERT_NOT_NULL(validatePage(page));
page.elements[0] = haElement(HaShow::Duration, DURATION_FORMAT_COUNT);
TEST_ASSERT_NOT_NULL(validatePage(page));
}
int main()
{
UNITY_BEGIN();
@@ -1856,6 +1985,10 @@ int main()
RUN_TEST(test_selector_one_block_starts_again_each_day);
RUN_TEST(test_selector_take_over_rules);
RUN_TEST(test_selector_add_to_rotation);
RUN_TEST(test_ha_auto_unit_and_absolute);
RUN_TEST(test_ha_duration);
RUN_TEST(test_ha_timestamps);
RUN_TEST(test_ha_text_map);
return UNITY_END();
}