Skip to content

Commit

Permalink
Merge pull request #198 from nhjschulz/feature/analogclock_config
Browse files Browse the repository at this point in the history
DateTimePlugin: Adding analog clock view configuration
  • Loading branch information
BlueAndi authored Nov 6, 2024
2 parents 99fabdf + 9f39572 commit 1235ccb
Show file tree
Hide file tree
Showing 8 changed files with 586 additions and 105 deletions.
120 changes: 111 additions & 9 deletions lib/DateTimePlugin/src/DateTimePlugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,23 @@
*****************************************************************************/

/* Initialize plugin topic. */
const char* DateTimePlugin::TOPIC_CONFIG = "/dateTime";
const char DateTimePlugin::TOPIC_CONFIG[] = "/dateTime";

/* Initialize default time format. */
const char* DateTimePlugin::TIME_FORMAT_DEFAULT = "%I:%M %p";
const char DateTimePlugin::TIME_FORMAT_DEFAULT[] = "%I:%M %p";

/* Initialize default date format. */
const char* DateTimePlugin::DATE_FORMAT_DEFAULT = "%m/%d";
const char DateTimePlugin::DATE_FORMAT_DEFAULT[] = "%m/%d";

/* Color key names for the analog clock configuration. */
const char* DateTimePlugin::ANALOG_CLOCK_COLOR_KEYS[IDateTimeView::ANA_CLK_COL_MAX] =
{
"handHourCol",
"handMinCol",
"handSecCol",
"ringFiveMinCol",
"ringMinDotCol"
};

/******************************************************************************
* Public Methods
Expand Down Expand Up @@ -95,18 +105,22 @@ bool DateTimePlugin::setTopic(const String& topic, const JsonObjectConst& value)

if (true == topic.equals(TOPIC_CONFIG))
{
const size_t JSON_DOC_SIZE = 512U;
const IDateTimeView::AnalogClockConfig* analogClockCfg = nullptr;

const size_t JSON_DOC_SIZE = 768U;
DynamicJsonDocument jsonDoc(JSON_DOC_SIZE);
JsonObject jsonCfg = jsonDoc.to<JsonObject>();
JsonVariantConst jsonMode = value["mode"];
JsonVariantConst jsonViewMode = value["viewMode"];
JsonVariantConst jsonTimeFormat = value["timeFormat"];
JsonVariantConst jsonDateFormat = value["dateFormat"];
JsonVariantConst jsonTimeZone = value["timeZone"];
JsonVariantConst jsonStartOfWeek = value["startOfWeek"];
JsonVariantConst jsonDayOnColor = value["dayOnColor"];
JsonVariantConst jsonDayOffColor = value["dayOffColor"];

/* The received configuration may not contain all single key/value pair.
JsonObjectConst jsonAnalogClock = value["analogClock"];

/* The received configuration may not contain all single key/value pair.
* Therefore read first the complete internal configuration and
* overwrite them with the received ones.
*/
Expand All @@ -122,7 +136,13 @@ bool DateTimePlugin::setTopic(const String& topic, const JsonObjectConst& value)
jsonCfg["mode"] = jsonMode.as<uint8_t>();
isSuccessful = true;
}


if (false == jsonViewMode.isNull())
{
jsonCfg["viewMode"] = jsonViewMode.as<uint8_t>();
isSuccessful = true;
}

if (false == jsonTimeFormat.isNull())
{
jsonCfg["timeFormat"] = jsonTimeFormat.as<String>();
Expand Down Expand Up @@ -158,6 +178,12 @@ bool DateTimePlugin::setTopic(const String& topic, const JsonObjectConst& value)
jsonCfg["dayOffColor"] = jsonDayOffColor.as<String>();
isSuccessful = true;
}

if (false == jsonAnalogClock.isNull())
{
jsonCfg["analogClock"] = jsonAnalogClock;
isSuccessful = true;
}

if (true == isSuccessful)
{
Expand Down Expand Up @@ -262,33 +288,59 @@ void DateTimePlugin::update(YAGfx& gfx)

void DateTimePlugin::getConfiguration(JsonObject& jsonCfg) const
{
const IDateTimeView::AnalogClockConfig* analogClockCfg = nullptr;

MutexGuard<MutexRecursive> guard(m_mutex);

jsonCfg["mode"] = m_mode;
jsonCfg["viewMode"] = m_view.getViewMode();
jsonCfg["timeFormat"] = m_timeFormat;
jsonCfg["dateFormat"] = m_dateFormat;
jsonCfg["timeZone"] = m_timeZone;
jsonCfg["startOfWeek"] = m_view.getStartOfWeek();
jsonCfg["dayOnColor"] = colorToHtml(m_view.getDayOnColor());
jsonCfg["dayOffColor"] = colorToHtml(m_view.getDayOffColor());

analogClockCfg = m_view.getAnalogClockConfig();
if (nullptr != analogClockCfg)
{
/* View supports analog clock, add the additinal config elements for it.
*/
JsonObject jsonAnalogClock = jsonCfg.createNestedObject("analogClock");
jsonAnalogClock["secondsMode"] = analogClockCfg->m_secondsMode;
for (uint32_t index = 0U; index < IDateTimeView::ANA_CLK_COL_MAX; ++index)
{
jsonAnalogClock[ANALOG_CLOCK_COLOR_KEYS[index]]= colorToHtml(analogClockCfg->m_colors[index]);
}
}

}

bool DateTimePlugin::setConfiguration(const JsonObjectConst& jsonCfg)
{
bool status = false;
JsonVariantConst jsonMode = jsonCfg["mode"];
JsonVariantConst jsonViewMode = jsonCfg["viewMode"];
JsonVariantConst jsonTimeFormat = jsonCfg["timeFormat"];
JsonVariantConst jsonDateFormat = jsonCfg["dateFormat"];
JsonVariantConst jsonTimeZone = jsonCfg["timeZone"];
JsonVariantConst jsonStartOfWeek = jsonCfg["startOfWeek"];
JsonVariantConst jsonDayOnColor = jsonCfg["dayOnColor"];
JsonVariantConst jsonDayOffColor = jsonCfg["dayOffColor"];
JsonVariantConst jsonAnalogClock = jsonCfg["analogClock"];

IDateTimeView::AnalogClockConfig analogClockConfig;

if ((false == jsonMode.is<uint8_t>()) &&
(MODE_MAX <= jsonMode.as<uint8_t>()))
{
LOG_WARNING("JSON mode not found or invalid type.");
}
else if ((false == jsonViewMode.is<uint8_t>()) &&
(IDateTimeView::VIEW_MODE_MAX <= jsonViewMode.as<uint8_t>()))
{
LOG_WARNING("JSON view mode not found or invalid type.");
}
else if (false == jsonTimeFormat.is<String>())
{
LOG_WARNING("JSON time format not found or invalid type.");
Expand All @@ -313,6 +365,10 @@ bool DateTimePlugin::setConfiguration(const JsonObjectConst& jsonCfg)
{
LOG_WARNING("JSON day off color not found or invalid type.");
}
else if (false == checkAnalogClockConfig(jsonAnalogClock, analogClockConfig))
{
/* Error printed inside checkAnalogClockConfig() already. */
}
else
{
MutexGuard<MutexRecursive> guard(m_mutex);
Expand All @@ -325,6 +381,12 @@ bool DateTimePlugin::setConfiguration(const JsonObjectConst& jsonCfg)
status = m_view.setStartOfWeek(jsonStartOfWeek.as<uint8_t>());
m_view.setDayOnColor(colorFromHtml(jsonDayOnColor.as<String>()));
m_view.setDayOffColor(colorFromHtml(jsonDayOffColor.as<String>()));
m_view.setViewMode(static_cast<IDateTimeView::ViewMode>(jsonViewMode.as<uint8_t>()));

if (false == jsonAnalogClock.isNull())
{
m_view.setAnalogClockConfig(analogClockConfig);
}

m_hasTopicChanged = true;
}
Expand Down Expand Up @@ -511,7 +573,7 @@ bool DateTimePlugin::getTimeAsString(String& time, const String& format, const t
return isSuccessful;
}

String DateTimePlugin::colorToHtml(const Color& color) const
String DateTimePlugin::colorToHtml(const Color& color)
{
char buffer[8]; /* '#' + 3x byte in hex + '\0' */

Expand All @@ -520,7 +582,7 @@ String DateTimePlugin::colorToHtml(const Color& color) const
return String(buffer);
}

Color DateTimePlugin::colorFromHtml(const String& htmlColor) const
Color DateTimePlugin::colorFromHtml(const String& htmlColor)
{
Color color;

Expand All @@ -532,6 +594,46 @@ Color DateTimePlugin::colorFromHtml(const String& htmlColor) const
return color;
}

bool DateTimePlugin::checkAnalogClockConfig(JsonVariantConst& jsonCfg, IDateTimeView::AnalogClockConfig & cfg)
{
bool result = true;

if (false == jsonCfg.isNull())
{
JsonVariantConst jsonSecondsMode = jsonCfg["secondsMode"];

if ((false == jsonSecondsMode.is<uint8_t>()) &&
(IDateTimeView::SECONDS_DISP_MAX <= jsonSecondsMode.as<uint8_t>()))
{
LOG_WARNING("JSON seconds mode not found or invalid type.");
result = false;
}
else
{
cfg.m_secondsMode = static_cast<IDateTimeView::SecondsDisplayMode>(jsonSecondsMode.as<uint8_t>());

for (uint32_t idx = 0U; idx < IDateTimeView::ANA_CLK_COL_MAX; ++ idx)
{
JsonVariantConst color = jsonCfg[ANALOG_CLOCK_COLOR_KEYS[idx]];

if (false == color.is<String>())
{
LOG_WARNING(
"JSON attribute %s not found or invalid type.",
ANALOG_CLOCK_COLOR_KEYS[idx]);
result = false;
}
else
{
cfg.m_colors[idx] = colorFromHtml(color);
}
}
}
}

return result;
}

/******************************************************************************
* External Functions
*****************************************************************************/
Expand Down
24 changes: 19 additions & 5 deletions lib/DateTimePlugin/src/DateTimePlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ class DateTimePlugin : public PluginWithConfig
/**
* Plugin topic, used to read/write the configuration.
*/
static const char* TOPIC_CONFIG;
static const char TOPIC_CONFIG[];

/** Time to check date update period in ms */
static const uint32_t CHECK_UPDATE_PERIOD = SIMPLE_TIMER_SECONDS(1U);
Expand All @@ -288,10 +288,13 @@ class DateTimePlugin : public PluginWithConfig
static const uint32_t MS_TO_SEC_DIVIDER = 1000U;

/** Default time format according to strftime(). */
static const char* TIME_FORMAT_DEFAULT;
static const char TIME_FORMAT_DEFAULT[];

/** Default date format according to strftime(). */
static const char* DATE_FORMAT_DEFAULT;
static const char DATE_FORMAT_DEFAULT[];

/** Color key names for the analog clock configuration. */
static const char* ANALOG_CLOCK_COLOR_KEYS[IDateTimeView::ANA_CLK_COL_MAX];

/**
* If the slot duration is infinite (0s), the default duration of 30s shall be assumed as base
Expand Down Expand Up @@ -359,7 +362,7 @@ class DateTimePlugin : public PluginWithConfig
*
* @return Color in HTML format
*/
String colorToHtml(const Color& color) const;
static String colorToHtml(const Color& color);

/**
* Convert color from HTML format.
Expand All @@ -368,7 +371,18 @@ class DateTimePlugin : public PluginWithConfig
*
* @return Color
*/
Color colorFromHtml(const String& htmlColor) const;
static Color colorFromHtml(const String& htmlColor);

/**
* Check if analog cfg is valid when present.
*
* @param jsonCfg[in] The json configuration, may be isNull().
* @param cfg[out] The parsed config data if json present and valid.
* @return true If no configuration or valid json values.
*/
static bool checkAnalogClockConfig(
JsonVariantConst& jsonCfg,
IDateTimeView::AnalogClockConfig & cfg);
};

/******************************************************************************
Expand Down
Loading

0 comments on commit 1235ccb

Please sign in to comment.