Browse Source

a simple scheduler for relays

i18n
Stefano Cotterli 6 years ago
parent
commit
b7ed0ec686
6 changed files with 234 additions and 3 deletions
  1. +101
    -0
      code/espurna/ascheduler.ino
  2. +4
    -0
      code/espurna/config/hardware.h
  3. +6
    -0
      code/espurna/espurna.ino
  4. +7
    -1
      code/html/custom.css
  5. +65
    -2
      code/html/custom.js
  6. +51
    -0
      code/html/index.html

+ 101
- 0
code/espurna/ascheduler.ino View File

@ -0,0 +1,101 @@
/*
A SCHEDULER MODULE
Copyright (C) 2017 by faina09
*/
#if SCHEDULER_SUPPORT
#include <NtpClientLib.h>
void _schWebSocketOnSend(JsonObject &root){
root["maxScheduled"] = MAX_SCHEDULED;
JsonArray &sch = root.createNestedArray("schedule");
for (byte i = 0; i < MAX_SCHEDULED; i++) {
if (!hasSetting("sch_switch", i))
break;
JsonObject &scheduler = sch.createNestedObject();
scheduler["sch_switch"] = getSetting("sch_switch", i, "");
scheduler["sch_operation"] = getSetting("sch_operation", i, "");
scheduler["sch_hour"] = getSetting("sch_hour", i, "");
scheduler["sch_minute"] = getSetting("sch_minute", i, "");
scheduler["sch_weekdays"] = getSetting("sch_weekdays", i, "");
}
}
void schSetup(){
// Update websocket clients
#if WEB_SUPPORT
wsOnSendRegister(_schWebSocketOnSend);
#endif
int i;
for (i = 0; i < MAX_SCHEDULED; i++) {
if (getSetting("sch_switch" + String(i)).length() == 0)
break;
String sch_weekdays = getSetting("sch_weekdays" + String(i));
int sch_switch = getSetting("sch_switch" + String(i)).toInt();
int sch_operation = getSetting("sch_operation" + String(i)).toInt();
int sch_hour = getSetting("sch_hour" + String(i)).toInt();
int sch_minute = getSetting("sch_minute" + String(i)).toInt();
DEBUG_MSG_P(PSTR("[SCH] Turn switch #%d %d AT %02d:%02d ON %s\n"), sch_switch, sch_operation, sch_hour, sch_minute, (char *)sch_weekdays.c_str());
}
}
void schLoop(){
// Check if we should compare scheduled and actual times
// TODO (?) start every minute and 0 seconds
static unsigned long last_update = 0;
static bool r_on = true;
if ((millis() - last_update > SCH_UPDATE_INTERVAL) || (last_update == 0)) {
last_update = millis();
int i;
for (i = 0; i < MAX_SCHEDULED; i++) {
if (getSetting("sch_switch" + String(i)).length() == 0)
break;
String sch_weekdays = getSetting("sch_weekdays" + String(i));
if (isThisWday(sch_weekdays)) {
int sch_switch = getSetting("sch_switch" + String(i)).toInt();
int sch_operation = getSetting("sch_operation" + String(i)).toInt();
int sch_hour = getSetting("sch_hour" + String(i)).toInt();
int sch_minute = getSetting("sch_minute" + String(i)).toInt();
DEBUG_MSG_P(PSTR("[SCH] Today it will turn switch #%d %d @ %02d:%02d\n"), sch_switch, sch_operation, sch_hour, sch_minute);
int minToTrigger = diffTime(sch_hour, sch_minute);
if (minToTrigger == 0) {
relayStatus(sch_switch, sch_operation);
DEBUG_MSG_P(PSTR("[SCH] TRIGGERED!!\n"));
}
if (minToTrigger < 0) {
//DEBUG_MSG_P(PSTR("[SCH] Time now: %s\n"), (char *)ntpDateTime().c_str()); // aaaa/mm/dd hh:mm:ss
DEBUG_MSG_P(PSTR("[SCH] Time now: %s, %d minutes to trigger %02d:%02d\n"), (char *)ntpDateTime().c_str(), minToTrigger, sch_hour, sch_minute);
}
}
}
}
}
bool isThisWday(String weekdays){
//Sunday = 1, Monday = 2, ...
int w = weekday(now());
//DEBUG_MSG_P(PSTR("[SCH] ntp weekday: %d\n"), w);
char * pch;
char * p = (char *)weekdays.c_str();
while ((pch = strtok_r(p, ",", &p)) != NULL) {
//DEBUG_MSG_P(PSTR("[SCH] w found: %d\n"), atoi(pch));
if (atoi(pch) == w) return true;
}
return false;
}
int diffTime(int schhour, int schminute){
if (!ntpConnected())
return 9999; //NTP time not set
String value = NTP.getTimeDateString();
int hour = value.substring(0, 2).toInt();
int minute = value.substring(3, 5).toInt();
//DEBUG_MSG_P(PSTR("[SCH] ntp time: %02d:%02d\n"), hour, minute);
//DEBUG_MSG_P(PSTR("[SCH] cmp time: %02d:%02d\n"), schhour, schminute);
return (hour - schhour) * 60 + minute - schminute;
}
#endif

+ 4
- 0
code/espurna/config/hardware.h View File

@ -39,6 +39,10 @@
#define RELAY1_PIN 12
#define RELAY1_TYPE RELAY_TYPE_NORMAL
#define SCHEDULER_SUPPORT 1
#define SCH_UPDATE_INTERVAL 30000
#define MAX_SCHEDULED 10
// LEDs
#define LED1_PIN 2
#define LED1_PIN_INVERSE 1


+ 6
- 0
code/espurna/espurna.ino View File

@ -383,6 +383,9 @@ void setup() {
#if SENSOR_SUPPORT
sensorSetup();
#endif
#if SCHEDULER_SUPPORT
schSetup();
#endif
// Prepare configuration for version 2.0
migrate();
@ -438,6 +441,9 @@ void loop() {
#if SENSOR_SUPPORT
sensorLoop();
#endif
#if SCHEDULER_SUPPORT
schLoop();
#endif
// Power saving delay
delay(_loopDelay);


+ 7
- 1
code/html/custom.css View File

@ -62,17 +62,23 @@
margin-left: 5px;
}
.button-add-network,
.button-add-schedule,
.button-rfb-learn {
background: rgb(28, 184, 65);
}
.button-del-network {
.button-del-network,
.button-del-schedule, {
background: rgb(202, 60, 60);
letter-spacing: 0px;
}
.button-more-network,
.button-more-schedule,
.button-rfb-send {
background: rgb(223, 117, 20);
}
#schedules input[type=number]{
max-width: 55px;
}
.button-settings-backup,
.button-settings-restore {
background: rgb(0, 202, 0);


+ 65
- 2
code/html/custom.js View File

@ -1,6 +1,7 @@
var websock;
var password = false;
var maxNetworks;
var maxSchedules;
var messages = [];
var webhost;
@ -43,7 +44,7 @@ function magnitudeType(type) {
var types = [
"Temperature", "Humidity", "Pressure",
"Current", "Voltage", "Active Power", "Apparent Power",
"Reactive Power", "Power Factor", "Energy", "Energy (delta)",
"Reactive Power", "Energy", "Energy (delta)", "Power Factor",
"Analog", "Digital", "Events",
"PM1.0", "PM2.5", "PM10", "CO2"
];
@ -100,6 +101,7 @@ function validateForm(form) {
// These fields will always be a list of values
var is_group = [
"ssid", "pass", "gw", "mask", "ip", "dns",
"sch_switch","sch_operation","sch_hour","sch_minute","sch_weekdays",
"relayBoot", "relayPulse", "relayTime",
"mqttGroup", "mqttGroupInv",
"dczRelayIdx",
@ -464,6 +466,39 @@ function moreNetwork() {
$(".more", parent).toggle();
}
// -----------------------------------------------------------------------------
// Relays scheduler
// -----------------------------------------------------------------------------
function delSchedule() {
var parent = $(this).parents(".pure-g");
$(parent).remove();
}
function moreSchedule() {
var parent = $(this).parents(".pure-g");
$("div.more", parent).toggle();
}
function addSchedule() {
var numSchedules = $("#schedules > div").length;
if (numSchedules >= maxSchedules) {
alert("Max number of schedules reached");
return;
}
var tabindex = 200 + numSchedules * 10;
var template = $("#scheduleTemplate").children();
var line = $(template).clone();
$(line).find("input").each(function() {
$(this).attr("tabindex", tabindex++);
});
$(line).find(".button-del-schedule").on('click', delSchedule);
$(line).find(".button-more-schedule").on('click', moreSchedule);
line.appendTo("#schedules");
return line;
}
// -----------------------------------------------------------------------------
// Relays
// -----------------------------------------------------------------------------
@ -817,6 +852,31 @@ function processData(data) {
return;
}
// -----------------------------------------------------------------------------
// Relays scheduler
// -----------------------------------------------------------------------------
if (key == "maxSchedules") {
maxSchedules = parseInt(data.maxSchedules);
return;
}
if (key == "schedule") {
var schedule = data.schedule;
for (var i in schedule) {
// add a new row
var line = addSchedule();
// fill in the blanks
var schedule = data.schedule[i];
Object.keys(schedule).forEach(function(key) {
var element = $("input[name=" + key + "]", line);
if (element.length) element.val(schedule[key]);
var elementsel = $("select[name=" + key + "]", line);
if (elementsel.length) elementsel.prop("value", schedule[key]);
});
}
return;
}
// ---------------------------------------------------------------------
// Relays
// ---------------------------------------------------------------------
@ -1036,7 +1096,10 @@ $(function() {
$(".button-add-network").on('click', function() {
$(".more", addNetwork()).toggle();
});
$(".button-add-schedule").on('click', function() {
$("div.more", addSchedule()).toggle();
});
$(document).on('change', 'input', hasChanged);
$(document).on('change', 'select', hasChanged);


+ 51
- 0
code/html/index.html View File

@ -100,6 +100,10 @@
<a href="#" class="pure-menu-link" data="panel-relay">SWITCHES</a>
</li>
<li class="pure-menu-item module module-relay">
<a href="#" class="pure-menu-link" data="panel-schedule">SCHEDULE</a>
</li>
<li class="pure-menu-item module module-color">
<a href="#" class="pure-menu-link" data="panel-color">LIGHTS</a>
</li>
@ -525,6 +529,22 @@
</div>
</div>
<div class="panel" id="panel-schedule">
<div class="header">
<h1>SCHEDULE</h1>
<h2>
Define actions based on the current time.
</h2>
</div>
<div class="page">
<fieldset>
<div id="schedules">
</div>
<button type="button" class="pure-button button-add-schedule">Add schedule</button>
</fieldset>
</div>
</div>
<div class="panel" id="panel-mqtt">
<div class="header">
@ -946,6 +966,37 @@
</div>
<div id="scheduleTemplate" class="template">
<div class="pure-g">
<label class="pure-u-sm-4-24 pure-u-1-3" for="sch_switch">Turn&nbsp;Switch&nbsp;No</label>
<div class="pure-u-sm-3-24 pure-u-1-3">
<input name="sch_switch" type="number" min="0" max="10" step="1" value="0" tabindex="0" />
</div>
<div class="pure-u-sm-3-24 pure-u-1-3">
<select name="sch_operation" tabindex="0">
<option value="0">OFF</option>
<option value="1">ON</option>
</select>
</div>
<label class="pure-u-sm-5-24 pure-u-1-3">at&nbsp;Time&nbsp;HH&nbsp;MM</label>
<div class="pure-u-sm-3-24 pure-u-1-3">
<input name="sch_hour" type="number" min="0" max="23" step="1" tabindex="0" value="0" />
</div>
<div class="pure-u-sm-3-24 pure-u-1-3">
<input name="sch_minute" type="number" min="0" max="59" step="1" tabindex="0" value="0" />
</div>
<div class="pure-u break"></div>
<label class="pure-u-sm-1-4 pure-u-1">on&nbsp;Weekdays:</label>
<div class="pure-u-sm-3-4 pure-u-1">
<div class="pure-u-1 weekDays-selector">
<input type="inbox" name="sch_weekdays" value="1,2,3,4,5,6,7" class="weekday" tabindex="0" />
</div>
<div class="pure-u-1 hint">1 = Sunday, 2 = Monday, ...</div>
</div>
<div class="pure-u-md-1-6 pure-u-1-4"><button type="button" class="pure-button button-del-schedule pure-u-5-6 pure-u-md-5-6">Del</button></div>
</div>
</div>
<div id="relayTemplate" class="template">
<div class="pure-g">
<div class="pure-u-1 pure-u-lg-1-4"><label>Switch #<span class="id"></span></label></div>


Loading…
Cancel
Save