initial commit
This commit is contained in:
commit
a09fd25462
246
pool.js
Normal file
246
pool.js
Normal 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();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user