initial commit

This commit is contained in:
Gilles Grandou 2022-04-21 09:32:39 +02:00
commit a09fd25462
1 changed files with 246 additions and 0 deletions

246
pool.js Normal file
View File

@ -0,0 +1,246 @@
print("[POOL] start");
let status = {
temp: null,
temp_max: null,
temp_today: null,
temp_yesterday: null,
update_time: null,
disable_temp: null,
tick_timer: 0,
tick_day: 0,
};
// compute duration of filtration for a given max temperature
// duration is returned in float format (1.25 -> 1h 15mn)
function compute_duration_filt(t) {
if (t < 5)
return 1;
if (t < 10)
return (t/5); // 1 -> 2
if (t < 12)
return (t-8); // 2 -> 4
if (t < 16)
return (t/2-2); // 4 -> 6
if (t < 24)
return (t/4+2); // 6 -> 8
if (t < 27)
return (t*4/3-24) // 8 -> 12
if (t < 30)
return (t*4 - 96); // 12 -> 24
return 24;
}
// compute the pump schedule for a given duration
// returns an array of start/stop times in float
// [ start1, stop1, start2, stop2, ... ]
function compute_schedule_filt(d) {
let s = null;
if (d < 2) {
s = [ 9, 9+d ];
} else if (d < 8) {
s = [ 9, 10, 14, 14+d-1 ];
} else if (d < 11) {
s = [ 9, 11, 14, 14+d-2 ];
} else if (d < 14) {
s = [ 9, 9+d-9, 14, 23];
} else if (d < 15) {
s = [ 9, 9+d ];
} else if (d < 18) {
s = [ 24-d, 0 ];
} else if (d < 24) {
s = [ 6, d-18 ];
} else {
s = [ 6 ];
}
return s;
}
// convert a time to a crontab-like timespec
function time_to_timespec(t) {
let h = Math.floor(t);
let m = Math.floor((t-h)*60);
let ts = "0 " + JSON.stringify(m) + " " + JSON.stringify(h) + " * * SUN,MON,TUE,WED,THU,FRI,SAT";
return ts;
}
// update temperature from Sensor
function update_temp(temp) {
print("[POOL] update_temp", temp);
if (status.disable_temp !== null) {
print("[POOL] updated disabled");
return;
}
status.temp = temp;
status.temp_today = Math.max(status.temp_today, temp);
status.temp_max = Math.max(status.temp_today, status.temp_yesterday);
print("[POOL] update_temp - max:", status.temp_max, "today:", status.temp_today, "yesterday:", status.temp_yesterday);
}
// new day, update status
function update_new_day() {
status.tick_day++;
print("[POOL] update_new_day", status.tick_day);
status.temp_yesterday = status.temp_today;
status.temp_today = null;
}
// call a chain of API calls
function do_call(calls) {
if (calls.length === 0) {
print("[POOL] call: done.");
return;
}
let m = calls[0].method;
let p = calls[0].params;
calls.splice(0, 1);
print("[POOL] call:", m, JSON.stringify(p));
Shelly.call(
m,
p,
function (r, errc, errm, _calls) {
do_call(_calls);
},
calls
);
}
// compute & configure pump schedule
// TODO force on when duration==24
// TODO force off when duration==0
// TODO freeze mode if cur < 1
function update_pump(temp, max, time) {
print("[POOL] update_pump", temp, max, time);
let duration = compute_duration_filt(max);
let schedule = compute_schedule_filt(duration);
print("[POOL] update_pump - duration:", duration);
print("[POOL] update_pump - schedule:", JSON.stringify(schedule));
let calls = [];
calls.push({method: "Schedule.DeleteAll", params: null});
let on = true;
for (let i = 0; i < schedule.length; i++) {
let ts = time_to_timespec(schedule[i]);
let p = {
id: i+1,
enable: true,
timespec: ts,
calls: [{
method: "Switch.Set",
params: { id: 0, on: on }
}]
};
calls.push({method: "Schedule.Create", params: p});
on = !on;
}
// compute the current switch state according to the schedule
let on = false;
let j = false;
for (let i = 0; i < schedule.length; i++) {
j = !j;
if (time >= schedule[i])
on = j;
}
calls.push({method: "Switch.Set", params: {id: 0, on: on}});
do_call(calls);
}
//
function update_pool() {
Shelly.call (
"Sys.GetStatus",
{},
function (result) {
let time = result.time; // "HH:MM"
print("[POOL] timer", time);
// compute current time in float format (12h45 -> 12.75)
let t = JSON.parse(time.slice(0,2)) + JSON.parse(time.slice(3,5)) / 60;
if (t < status.update_time)
update_new_day();
status.update_time = t;
if (status.temp_max !== null)
update_pump(status.temp, status.temp_max, t);
}
);
}
// receives updated from Pool Sensor
MQTT.subscribe(
"zigbee2mqtt/Piscine",
function (topic, msg) {
let obj = JSON.parse(msg);
if (obj.temperature === undefined) {
return;
}
update_temp(obj.temperature);
}
)
// after a Switch Event, disable temp update
// during 10 minutes
Shelly.addEventHandler(
function (data) {
if (data.info.event === "toggle") {
print("[POOL] disable temp");
if (status.disable_temp !== null)
Timer.clear(status.disable_temp);
status.disable_temp = Timer.set(
600 * 1000,
false,
function () {
print("[POOL] re-enable temp");
status.disable_temp = null;
}
);
}
}
);
// Run once per hour
// - update transition today -> yesterday
// - update pump schedule
Timer.set (
3600 * 1000,
true,
function () {
status.tick_timer++;
print("[POOL] timer", status.tick_timer);
update_pool();
}
);