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.

229 lines
7.1 KiB

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