Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
7.7 KiB

6 years ago
7 years ago
  1. /*
  2. SCHEDULER MODULE
  3. Copyright (C) 2017 by faina09
  4. Adapted by Xose Pérez <xose dot perez at gmail dot com>
  5. */
  6. #if SCHEDULER_SUPPORT
  7. #include <TimeLib.h>
  8. // -----------------------------------------------------------------------------
  9. #if WEB_SUPPORT
  10. bool _schWebSocketOnKeyCheck(const char * key, JsonVariant& value) {
  11. return (strncmp(key, "sch", 3) == 0);
  12. }
  13. void _schWebSocketOnVisible(JsonObject& root) {
  14. if (!relayCount()) return;
  15. root["schVisible"] = 1;
  16. }
  17. void _schWebSocketOnConnected(JsonObject &root){
  18. if (!relayCount()) return;
  19. root["maxSchedules"] = SCHEDULER_MAX_SCHEDULES;
  20. JsonObject &schedules = root.createNestedObject("schedules");
  21. uint8_t size = 0;
  22. JsonArray& enabled = schedules.createNestedArray("schEnabled");
  23. JsonArray& switch_ = schedules.createNestedArray("schSwitch");
  24. JsonArray& action = schedules.createNestedArray("schAction");
  25. JsonArray& type = schedules.createNestedArray("schType");
  26. JsonArray& hour = schedules.createNestedArray("schHour");
  27. JsonArray& minute = schedules.createNestedArray("schMinute");
  28. JsonArray& utc = schedules.createNestedArray("schUTC");
  29. JsonArray& weekdays = schedules.createNestedArray("schWDs");
  30. for (byte i = 0; i < SCHEDULER_MAX_SCHEDULES; i++) {
  31. if (!hasSetting("schSwitch", i)) break;
  32. ++size;
  33. enabled.add<uint8_t>(getSetting("schEnabled", i, 1).toInt() == 1);
  34. utc.add<uint8_t>(getSetting("schUTC", i, 0).toInt() == 1);
  35. switch_.add(getSetting("schSwitch", i, 0).toInt());
  36. action.add(getSetting("schAction", i, 0).toInt());
  37. type.add(getSetting("schType", i, 0).toInt());
  38. hour.add(getSetting("schHour", i, 0).toInt());
  39. minute.add(getSetting("schMinute", i, 0).toInt());
  40. weekdays.add(getSetting("schWDs", i, ""));
  41. }
  42. schedules["size"] = size;
  43. schedules["start"] = 0;
  44. }
  45. #endif // WEB_SUPPORT
  46. // -----------------------------------------------------------------------------
  47. void _schConfigure() {
  48. bool delete_flag = false;
  49. for (unsigned char i = 0; i < SCHEDULER_MAX_SCHEDULES; i++) {
  50. int sch_switch = getSetting("schSwitch", i, 0xFF).toInt();
  51. if (sch_switch == 0xFF) delete_flag = true;
  52. if (delete_flag) {
  53. delSetting("schEnabled", i);
  54. delSetting("schSwitch", i);
  55. delSetting("schAction", i);
  56. delSetting("schHour", i);
  57. delSetting("schMinute", i);
  58. delSetting("schWDs", i);
  59. delSetting("schType", i);
  60. delSetting("schUTC", i);
  61. } else {
  62. #if DEBUG_SUPPORT
  63. bool sch_enabled = getSetting("schEnabled", i, 1).toInt() == 1;
  64. int sch_action = getSetting("schAction", i, 0).toInt();
  65. int sch_hour = getSetting("schHour", i, 0).toInt();
  66. int sch_minute = getSetting("schMinute", i, 0).toInt();
  67. bool sch_utc = getSetting("schUTC", i, 0).toInt() == 1;
  68. String sch_weekdays = getSetting("schWDs", i, "");
  69. unsigned char sch_type = getSetting("schType", i, SCHEDULER_TYPE_SWITCH).toInt();
  70. DEBUG_MSG_P(
  71. PSTR("[SCH] Schedule #%d: %s #%d to %d at %02d:%02d %s on %s%s\n"),
  72. i, SCHEDULER_TYPE_SWITCH == sch_type ? "switch" : "channel", sch_switch,
  73. sch_action, sch_hour, sch_minute, sch_utc ? "UTC" : "local time",
  74. (char *) sch_weekdays.c_str(),
  75. sch_enabled ? "" : " (disabled)"
  76. );
  77. #endif // DEBUG_SUPPORT
  78. }
  79. }
  80. }
  81. bool _schIsThisWeekday(time_t t, String weekdays){
  82. // Convert from Sunday to Monday as day 1
  83. int w = weekday(t) - 1;
  84. if (0 == w) w = 7;
  85. char pch;
  86. char * p = (char *) weekdays.c_str();
  87. unsigned char position = 0;
  88. while ((pch = p[position++])) {
  89. if ((pch - '0') == w) return true;
  90. }
  91. return false;
  92. }
  93. int _schMinutesLeft(time_t t, unsigned char schedule_hour, unsigned char schedule_minute){
  94. unsigned char now_hour = hour(t);
  95. unsigned char now_minute = minute(t);
  96. return (schedule_hour - now_hour) * 60 + schedule_minute - now_minute;
  97. }
  98. void _schCheck() {
  99. time_t local_time = now();
  100. time_t utc_time = ntpLocal2UTC(local_time);
  101. // Check schedules
  102. for (unsigned char i = 0; i < SCHEDULER_MAX_SCHEDULES; i++) {
  103. int sch_switch = getSetting("schSwitch", i, 0xFF).toInt();
  104. if (sch_switch == 0xFF) break;
  105. // Skip disabled schedules
  106. if (getSetting("schEnabled", i, 1).toInt() == 0) continue;
  107. // Get the datetime used for the calculation
  108. bool sch_utc = getSetting("schUTC", i, 0).toInt() == 1;
  109. time_t t = sch_utc ? utc_time : local_time;
  110. String sch_weekdays = getSetting("schWDs", i, "");
  111. if (_schIsThisWeekday(t, sch_weekdays)) {
  112. int sch_hour = getSetting("schHour", i, 0).toInt();
  113. int sch_minute = getSetting("schMinute", i, 0).toInt();
  114. int minutes_to_trigger = _schMinutesLeft(t, sch_hour, sch_minute);
  115. if (minutes_to_trigger == 0) {
  116. unsigned char sch_type = getSetting("schType", i, SCHEDULER_TYPE_SWITCH).toInt();
  117. if (SCHEDULER_TYPE_SWITCH == sch_type) {
  118. int sch_action = getSetting("schAction", i, 0).toInt();
  119. DEBUG_MSG_P(PSTR("[SCH] Switching switch %d to %d\n"), sch_switch, sch_action);
  120. if (sch_action == 2) {
  121. relayToggle(sch_switch);
  122. } else {
  123. relayStatus(sch_switch, sch_action);
  124. }
  125. }
  126. #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
  127. if (SCHEDULER_TYPE_DIM == sch_type) {
  128. int sch_brightness = getSetting("schAction", i, -1).toInt();
  129. DEBUG_MSG_P(PSTR("[SCH] Set channel %d value to %d\n"), sch_switch, sch_brightness);
  130. lightChannel(sch_switch, sch_brightness);
  131. lightUpdate(true, true);
  132. }
  133. #endif
  134. DEBUG_MSG_P(PSTR("[SCH] Schedule #%d TRIGGERED!!\n"), i);
  135. // Show minutes to trigger every 15 minutes
  136. // or every minute if less than 15 minutes to scheduled time.
  137. // This only works for schedules on this same day.
  138. // For instance, if your scheduler is set for 00:01 you will only
  139. // get one notification before the trigger (at 00:00)
  140. } else if (minutes_to_trigger > 0) {
  141. #if DEBUG_SUPPORT
  142. if ((minutes_to_trigger % 15 == 0) || (minutes_to_trigger < 15)) {
  143. DEBUG_MSG_P(
  144. PSTR("[SCH] %d minutes to trigger schedule #%d\n"),
  145. minutes_to_trigger, i
  146. );
  147. }
  148. #endif
  149. }
  150. }
  151. }
  152. }
  153. void _schLoop() {
  154. // Check time has been sync'ed
  155. if (!ntpSynced()) return;
  156. // Check schedules every minute at hh:mm:00
  157. static unsigned long last_minute = 60;
  158. unsigned char current_minute = minute();
  159. if (current_minute != last_minute) {
  160. last_minute = current_minute;
  161. _schCheck();
  162. }
  163. }
  164. // -----------------------------------------------------------------------------
  165. void schSetup() {
  166. _schConfigure();
  167. // Update websocket clients
  168. #if WEB_SUPPORT
  169. wsRegister()
  170. .onVisible(_schWebSocketOnVisible)
  171. .onConnected(_schWebSocketOnConnected)
  172. .onKeyCheck(_schWebSocketOnKeyCheck);
  173. #endif
  174. // Main callbacks
  175. espurnaRegisterLoop(_schLoop);
  176. espurnaRegisterReload(_schConfigure);
  177. }
  178. #endif // SCHEDULER_SUPPORT