praegune kellaaeg 23.06.2025 13:57:24
|
Hinnavaatlus
:: Foorum
:: Uudised
:: Ärifoorumid
:: HV F1 ennustusvõistlus
:: Pangalink
:: Telekavad
:: HV toote otsing
|
|
autor |
|
matukas
HV vaatleja
liitunud: 21.01.2006
|
12.08.2024 15:38:05
|
|
|
aeropiloot kirjutas: |
matukas kirjutas: |
Kas keegi on kokku puutunud Atlantic boileri võrku ühendamise probleemiga läbi cozytouch rakenduse?
Kuidagi ei taha õnnestuda ja suppordist abi ei ole. Räägib, et meie regioonis tuleb kasutada google DNSi (8.8.8.8) ja avada tuleb port 804.
Samas NATistatud võrgust tavaolukorras väljaminev liiklus piiratud ei ole ja ma ei usu, et nad eeldavad sissetulevat portforwardi. DNSi sai vahetatud.
Telia fiiber, Mikrotik ruuter, Asuse AP. |
Mind ka huvitaks see juhend. Mul varem toimetas cozytouch edukalt ja sellel kevadel suvilas uuesti seisse lükates enam boiler rakenduses online ei tulnud. Kustutasin ära ja proovisin uuesti lisada aga enam ei õnnestu. Ei tea mis nad seal vahepeal käkerdasid. |
Mina ostsin FEBist Vertigo 80 Wif (https://www.feb.ee/et/vesi-ja-kanalisatsioon/boilerid-ja-varuosad/vertikaalsed-boilerid/atlantic/boiler-vertigo-80-65-l-max-2250w-wi-fi-hobe), seal on ka Juhendite sektsiooni alt saadaval tootja juhend ( https://www.feb.ee/tooted/PLASTOR/2203H/DOKUMENDID/juhend_1.pdf ) kuid see ei ütle errorite kohta midagi. Installid rakenduse ja proovid sealt kaudu ning kui ei õnnestu siis võtad ühendust suppordiga, kes siis vastab, et ida-euroopas justkui oleks see probleem, kasutage DNSi 8.8.8.8 ja avage port 804.
Juhendi lk 9 (või PDF lk 11).
5. Connectivity
This appliance has a Wi-Fi function which allows it to be activated or programmed remotely
via your smartphone or tablet.
To enable this, the following accessories are required:
• An Internet router or hub
• The Cozytouch application, compatible with IOS and Android.
Free download from app stores
iOS version 9.0 minimum Android version 4.1 minimum
After the application is installed, ensure you have the ID and password for your Internet router or hub and open the Cozytouch application. Follow the step-by-step instructions to create your account and then pair your appliance
|
|
tagasi üles |
|
 |
pois11
HV Guru
liitunud: 11.10.2003
|
12.08.2024 17:37:40
|
|
|
Ei saa shelly scripti nii tööle nagu minul tarvis on: https://github.com/LeivoSepp/Smart-heating-management-with-Shelly
Kasutan börsi jälgimise funktsiooni ilma kütmise funktsioonita. Kui hind on madalam siis relee on sees, ja kõrgem, siis OFF
Spoiler 
Probleem on selles, et arvestus käib ainult korra päevas kell 23:00, kui kogu ajaperioodil on börsi hind soodne nagu tavaliselt nv on, siis viimased 4 arvestus läheb kaduma. Relee on esimesed 20h sees, sest Shelly nutireleel on piirang 20 Schedule korraga. Oleks vaja, et script teeks kalkulatsiooni kaks korda ööpäevas. Kell 23:00 ja kell 11:00
Kuidas seda teha või saaks keegi aidata?
Minu script:
Spoiler 
/*
This Shelly script is designed to retrieve energy market prices from Elering and
activate heating during the most cost-effective hours each day, employing various algorithms.
1. Dynamic calculation of heating time for the next day based on weather forecasts.
2. Division of heating into time periods, with activation during the cheapest hour within each period.
3. Utilization of min-max price levels to maintain the Shelly system consistently on or off.
The script executes daily after 23:00 to establish heating timeslots for the following day.
created by Leivo Sepp, 25.12.2023
https://github.com/LeivoSepp/Smart-heating-management-with-Shelly
*/
/* Elektrilevi electricity transmission fees (EUR/MWh): */
let VORK1 = { dayRt: 72, nightRt: 72 };
let VORK2 = { dayRt: 87, nightRt: 50 };
let VORK2KUU = { dayRt: 56, nightRt: 33 };
let VORK4 = { dayRt: 37, nightRt: 21 };
let NONE = { dayRt: 0, nightRt: 0 };
// timePeriod: duration of each time period in hours, (0 -> only min-max price used, 24 -> period is one day).
// heatingTime: duration of heating in hours during each designated period.
// isFcstUsed: true/false - Using weather forecast to calculate heating duration.
/****** HEATING MODES, YOU CAN MODIFY OR CREATE YOUR OWN ******/
/* Heating schedulers with forecast */
let HEAT24H_FCST = { timePeriod: 24, heatingTime: 0, isFcstUsed: true };
let HEAT12H_FCST = { timePeriod: 12, heatingTime: 24, isFcstUsed: true };
let HEAT6H_FCST = { timePeriod: 6, heatingTime: 0, isFcstUsed: true };
/* 24h heating schedulers */
let HEAT24H_20H = { timePeriod: 24, heatingTime: 20, isFcstUsed: false };
let HEAT24H_12H = { timePeriod: 24, heatingTime: 12, isFcstUsed: false };
let HEAT24H_10H = { timePeriod: 24, heatingTime: 10, isFcstUsed: false };
let HEAT24H_8H = { timePeriod: 24, heatingTime: 8, isFcstUsed: false };
/* 12h heating schedulers */
let HEAT12H_6H = { timePeriod: 12, heatingTime: 6, isFcstUsed: false };
let HEAT12H_4H = { timePeriod: 12, heatingTime: 4, isFcstUsed: false };
let HEAT12H_2H = { timePeriod: 12, heatingTime: 2, isFcstUsed: false };
let HEAT12H_1H = { timePeriod: 12, heatingTime: 1, isFcstUsed: false };
/* 6h heating schedulers */
let HEAT6H_2H = { timePeriod: 6, heatingTime: 2, isFcstUsed: false };
let HEAT6H_1H = { timePeriod: 6, heatingTime: 1, isFcstUsed: false };
/* 4h heating schedulers */
let HEAT4H_2H = { timePeriod: 4, heatingTime: 2, isFcstUsed: false };
let HEAT4H_1H = { timePeriod: 4, heatingTime: 1, isFcstUsed: false };
/* Use only low price component */
let HEAT_LOWPRICE = { timePeriod: 12, heatingTime: 12, isFcstUsed: false };
/****** USER SETTINGS, START MODIFICATION ******/
let s = {
heatingMode: HEAT_LOWPRICE , // HEATING MODE. Different heating modes described above.
elektrilevi: NONE , // ELEKTRILEVI transmission fee: VORK1 / VORK2 / VORK2KUU / VORK4 / NONE
// alwaysOnLowPrice: 10, // Keep heating always ON if energy price lower than this value (EUR/MWh)
alwaysOffHighPrice: 250, // Keep heating always OFF if energy price higher than this value (EUR/MWh)
isOutputInverted: false, // Configures the relay state to either normal or inverted. (inverted required by Nibe, Thermia)
relayID: 0, // Shelly relay ID
defaultTimer: 60, // Default timer duration, in minutes, for toggling the Shelly state.
country: "ee", // Estonia-ee, Finland-fi, Lithuania-lt, Latvia-lv
heatingCurve: 1, // Shifting heating curve to the left or right, check the tables below. Shift by 1 equals 1h.
powerFactor: 1, // Adjusts the heating curve to be either more flat or more aggressive (0 -> flat, 1 -> steep).
}
/****** USER SETTINGS, END OF MODIFICATION ******/
/*
Heating time dependency on heating curve and outside temperature for 24h and 12h (power factor 0.5).
| ------ 24h heating curve ------ |
°C |-10 -8 -6 -4 -2 0 2 4 6 8 10
_________________________________________________
17 | 0 0 0 0 0 0 0 0 0 0 0
15 | 0 0 0 0 0 0 0 2 4 6 8
10 | 0 0 0 0 0 1 3 5 7 9 11
5 | 0 0 0 0 1 3 5 7 9 11 13
0 | 0 0 0 2 4 6 8 10 12 14 16
-5 | 0 0 2 4 6 8 10 12 14 16 18
-10 | 1 3 5 7 9 11 13 15 17 19 21
-15 | 3 5 7 9 11 13 15 17 19 21 23
-20 | 6 8 10 12 14 16 18 20 22 24 24
-25 | 8 10 12 14 16 18 20 22 24 24 24
| ------- 12h heating curve ------- |
°C |-10 -8 -6 -4 -2 0 2 4 6 8 10
_________________________________________________
17 | 0 0 0 0 0 0 0 0 0 0 0
15 | 0 0 0 0 0 0 0 1 2 3 4
10 | 0 0 0 0 0 1 2 3 4 5 6
5 | 0 0 0 0 1 2 3 4 5 6 7
0 | 0 0 0 1 2 3 4 5 6 7 8
-5 | 0 0 1 2 3 4 5 6 7 8 9
-10 | 1 2 3 4 5 6 7 8 9 10 11
-15 | 2 3 4 5 6 7 8 9 10 11 12
-20 | 3 4 5 6 7 8 9 10 11 12 12
-25 | 4 5 6 7 8 9 10 11 12 12 12
Forecast temp °C is "feels like": more information here: https://en.wikipedia.org/wiki/Apparent_temperature
*/
let _ = {
openMeteo: "https://api.open-meteo.com/v1/forecast?hourly=apparent_temperature&timezone=auto&forecast_days=1&forecast_hours=" + s.heatingMode.timePeriod,
elering: "https://dashboard.elering.ee/api/nps/price/csv?fields=" + s.country,
elUrl: '',
omUrl: '',
heatTime: '',
ctPeriods: s.heatingMode.timePeriod <= 0 ? 0 : Math.ceil((24 * 100) / (s.heatingMode.timePeriod * 100)), //period count is up-rounded
tsPrices: '',
tsFcst: '',
loopFreq: 60, //seconds
loopRunning: false,
dayInSec: 60 * 60 * 24,
sId: Shelly.getCurrentScriptId(),
pId: "Id" + Shelly.getCurrentScriptId() + ": ",
rpcCl: 3,
cntr: 0,
schedId: [],
version: 2.6,
};
/*
This is the start of the script.
Set the script to start automatically.
Set the default script library
Get old scheduler IDs from the KVS storage
*/
function start() {
setAutoStart();
setKvsScrLibr();
Shelly.call('KVS.Get', { key: "schedulerIDs" + _.sId }, function (res, err, msg, data) {
let si = [];
if (res) {
si = JSON.parse(res.value);
res = null; //to save memory
}
delSc(si);
});
}
/* set the script to sart automatically on boot */
function setAutoStart() {
if (!Shelly.getComponentConfig("script", _.sId).enable) {
Shelly.call('Script.SetConfig', { id: _.sId, config: { enable: true } },
function (res, err, msg, data) {
if (err != 0) {
print("Heating script autostart is not enabled.", msg, ". After Shelly restart, this script will not start and new heating schedules are not created.");
}
});
}
}
/* set the default script library */
function setKvsScrLibr() {
Shelly.call("KVS.set", { key: "scripts-library", value: '{"url": "https://raw.githubusercontent.com/LeivoSepp/Smart-heating-management-with-Shelly/master/manifest.json"}' });
}
/*
Before anything else delete all the old schedulers created by this script.
*/
function delSc(s) {
//logic below is a non-blocking method for RPC calls to delete all schedulers one by one
if (_.cntr < 6 - _.rpcCl) {
for (let i = 0; i < _.rpcCl && i < s.length; i++) {
let id = s.splice(0, 1)[0];
_.cntr++;
Shelly.call("Schedule.Delete", { id: id },
function (res, err, msg, data) {
if (err !== 0) {
print(_.pId, "Schedule ", data.id, " delete FAILED.");
}
else {
print(_.pId, "Schedule ", data.id, " delete SUCCEEDED.");
}
_.cntr--;
},
{ id: id }
);
}
}
//if there are more calls in the queue
if (s.length > 0) {
Timer.set(
1000, //the delay
false,
function () {
delSc(s);
});
}
else {
main(); //start the main logic
}
}
/**
This is the main script where all the logic starts.
This one is called after all the old schedulers are deleted.
*/
function main() {
//wait until all the schedulers are deleted
if (_.cntr !== 0) {
Timer.set(
1000,
false,
function () {
main();
});
return;
}
//all old schedulers are now deleted, start the main flow
//find Shelly timezone
let shEpochUtc = Shelly.getComponentStatus("sys").unixtime;
let shDt = new Date(shEpochUtc * 1000);
let shHr = shDt.getHours();
let shUtcHr = shDt.toISOString().slice(11, 13);
let tz = shHr - shUtcHr;
if (tz > 12) { tz -= 24; }
if (tz < -12) { tz += 24; }
let tzInSec = tz * 60 * 60;
// After 23:00 tomorrow's energy prices are used
// before 23:00 today's energy prices are used.
let addDays = shHr >= 23 ? 0 : -1;
// build datetime for Elering query
let isoTime = new Date((shEpochUtc + tzInSec + _.dayInSec * addDays) * 1000).toISOString().slice(0, 10);
let isoTimePlusDay = new Date((shEpochUtc + tzInSec + (_.dayInSec * (addDays + 1))) * 1000).toISOString().slice(0, 10);
let dtStart = isoTime + "T" + (24 - tz) + ":00Z";
let dtEnd = isoTimePlusDay + "T" + (24 - tz - 1) + ":00Z";
_.elUrl = _.elering + "&start=" + dtStart + "&end=" + dtEnd;
print(_.pId, "Shelly ", shDt);
shDt = null;
shEpochUtc = null;
_.heatTime = s.heatingMode.heatingTime;
//if weather forecast used for heating hours
s.heatingMode.isFcstUsed ? getForecast() : getElering();
}
/**
Get Open-Meteo min and max "feels like" temperatures
*/
function getForecast() {
let lat = JSON.stringify(Shelly.getComponentConfig("sys").location.lat);
let lon = JSON.stringify(Shelly.getComponentConfig("sys").location.lon);
_.omUrl = _.openMeteo + "&latitude=" + lat + "&longitude=" + lon;
print(_.pId, "Get forecast from: ", _.omUrl)
try {
Shelly.call("HTTP.GET", { url: _.omUrl, timeout: 5, ssl_ca: "*" }, fcstCalc);
}
catch (error) {
print(_.pId, "Oh no, OpenMeteo ", error);
print(_.pId, "Get forecast failed, checking again in ", _.loopFreq, " seconds.");
_.loopRunning = false;
}
}
/* Calculate heating hours */
function fcstCalc(res, err, msg) {
try {
if (err != 0 || res === null || res.code != 200 || JSON.parse(res.body)["error"]) {
print(_.pId, "Get forecast failed, checking again in ", _.loopFreq, " seconds.");
_.loopRunning = false;
}
else {
let jsonFcst = JSON.parse(res.body); //open-meteo json response
let aTemp = jsonFcst["hourly"]["apparent_temperature"]; //get 6h, 12h or 24h temperatures
let sumFcst = 0;
for (let i = 0; i < aTemp.length; i++) {
sumFcst += aTemp[i];
}
//clear memory
aTemp = null;
res = null;
jsonFcst = null;
let tempFcst = Math.ceil(sumFcst / s.heatingMode.timePeriod); //AVG and round temperature up
_.tsFcst = epoch(); //store the timestamp into memory
print(_.pId, "We got weather forecast from Open Meteo at ", new Date().toString());
// calculating heating hours
let startTemp = 16;
let fcstHeatTime = ((startTemp - tempFcst) * (s.powerFactor - 1) + (startTemp - tempFcst + s.heatingCurve - 2));
fcstHeatTime = fcstHeatTime < 0 || tempFcst > startTemp ? 0 : fcstHeatTime; //heating time can't be negative
_.heatTime = Math.floor(fcstHeatTime / _.ctPeriods); //divide with periods and round-down heating duration
_.heatTime = _.heatTime > s.heatingMode.timePeriod ? s.heatingMode.timePeriod : _.heatTime; //heating time can't be more than period
print(_.pId, "Temperture forecast width windchill is ", tempFcst, " °C, and heating enabled for ", _.heatTime, " hours.");
getElering(); //call elering
}
} catch (error) {
print(_.pId, "Oh no, OpenMeteo JSON ", error);
print(_.pId, "Get forecast failed, checking again in ", _.loopFreq, " seconds.");
_.loopRunning = false;
}
}
/* Get electricity market price CSV file from Elering. */
function getElering() {
print(_.pId, "Get Elering prices from: ", _.elUrl);
try {
Shelly.call("HTTP.GET", { url: _.elUrl, timeout: 5, ssl_ca: "*" }, priceCalc);
}
catch (error) {
print(_.pId, "Oh no, Elering ", error);
print(_.pId, "Get Elering failed, checking again in ", _.loopFreq, " seconds.");
_.loopRunning = false;
}
}
/**
Price calculation logic.
Creating time periods etc.
*/
function priceCalc(res, err, msg) {
if (err != 0 || res === null || res.code != 200 || !res.body_b64) {
print(_.pId, "Get Elering failed, checking again in ", _.loopFreq, " seconds.");
_.loopRunning = false;
}
else {
//clear memory
res.headers = null;
res.message = null;
msg = null;
//Converting base64 to text
res.body_b64 = atob(res.body_b64);
//Discarding header
res.body_b64 = res.body_b64.substring(res.body_b64.indexOf("\n") + 1);
let eleringPrices = [];
let activePos = 0;
while (activePos >= 0) {
res.body_b64 = res.body_b64.substring(activePos);
activePos = 0;
let row = [0, 0];
activePos = res.body_b64.indexOf("\"", activePos) + 1;
if (activePos === 0) {
//" character not found -> end of data
break;
}
//epoch
row[0] = Number(res.body_b64.substring(activePos, res.body_b64.indexOf("\"", activePos)));
//skip "; after timestamp
activePos = res.body_b64.indexOf("\"", activePos) + 2;
//price
activePos = res.body_b64.indexOf(";\"", activePos) + 2;
row[1] = Number(res.body_b64.substring(activePos, res.body_b64.indexOf("\"", activePos)).replace(",", "."));
//Add transfer fees (if any)
let hour = new Date(row[0] * 1000).getHours();
let day = new Date(row[0] * 1000).getDay();
if (hour < 7 || hour >= 22 || day === 6 || day === 0) {
row[1] += s.elektrilevi.nightRt; //night fee
}
else {
row[1] += s.elektrilevi.dayRt; //day fee
}
//Adding stuff
eleringPrices.push(row);
//find next row
activePos = res.body_b64.indexOf("\n", activePos);
}
res = null; //to save memory
let newScheds = [];
//store the timestamp into memory
_.tsPrices = epoch();
print(_.pId, "We got market prices from Elering ", new Date().toString());
setShellyTimer(s.isOutputInverted, s.defaultTimer); //set default timer
//if heating is based only on the alwaysOnMaxPrice and alwaysOffMinPrice
if (s.heatingMode.timePeriod <= 0) {
for (let a = 0; a < eleringPrices.length; a++) {
if (eleringPrices[a][1] < s.alwaysOnLowPrice) {
newScheds.push([new Date((eleringPrices[a][0]) * 1000).getHours(), eleringPrices[a][1], 0]);
print(_.pId, "Energy price + transfer fee " + eleringPrices[a][1] + " EUR/MWh at " + new Date((eleringPrices[a][0]) * 1000).getHours() + ":00 is less than min price and used for heating.")
}
}
if (!newScheds.length) {
print(_.pId, "No energy prices below min price level. No heating.")
}
}
//heating periods calculation
let period = [];
let sortedPeriod = [];
//the number of period when the script is executed in case of forecast used
let nmPeriod = Math.ceil((new Date().getHours() % 23 + 2) / s.heatingMode.timePeriod);
// Create an array for each heating period, sort, and push the prices
for (let i = 0; i < _.ctPeriods; i++) {
if (s.heatingMode.isFcstUsed && (i + 1) != nmPeriod) { continue; } //in case of forecast, only one period is calculated
let k = 0;
let hoursInPeriod = (i + 1) * s.heatingMode.timePeriod > 24 ? 24 : (i + 1) * s.heatingMode.timePeriod;
for (let j = i * s.heatingMode.timePeriod; j < hoursInPeriod; j++) {
period[k] = eleringPrices[j];
k++;
}
sortedPeriod = sort(period, 1); //sort by price
let heatingHours = sortedPeriod.length < _.heatTime ? sortedPeriod.length : _.heatTime; //finds max hours to heat in that period
for (let a = 0; a < sortedPeriod.length; a++) {
if ((a < heatingHours || sortedPeriod[a][1] < s.alwaysOnLowPrice) && !(sortedPeriod[a][1] > s.alwaysOffHighPrice)) {
newScheds.push([new Date((sortedPeriod[a][0]) * 1000).getHours(), sortedPeriod[a][1], i + 1]);
}
//If some hours are too expensive to use for heating, then just let user know for this
if (a < heatingHours && sortedPeriod[a][1] > s.alwaysOffHighPrice) {
print(_.pId, "Energy price + transfer fee " + sortedPeriod[a][1] + " EUR/MWh at " + new Date((sortedPeriod[a][0]) * 1000).getHours() + ":00 is more expensive than max price and not used for heating.")
}
}
}
//clearing memory
eleringPrices = null;
sortedPeriod = null;
period = null;
}
listScheds(sort(newScheds, 0));
}
/**
Get all the existing schedulers to check duplications
*/
function listScheds(newScheds) {
Shelly.call("Schedule.List", {},
function (res, err, msg, data) {
if (res === 0) {
// No existing schedulers found
createScheds([], data.s);
}
else {
// Found existing schedulers
createScheds(res.jobs, data.s);
res = null; //to save memory
}
}, { s: newScheds }
);
}
/**
Create all schedulers, the Shelly limit is 20.
*/
function createScheds(listScheds, newScheds) {
//logic below is a non-blocking method for RPC calls to create all schedulers one by one
if (_.cntr < 6 - _.rpcCl) {
for (let i = 0; i < _.rpcCl && i < newScheds.length; i++) {
let isExist = false;
let hour = newScheds[0][0];
let ctPeriod = newScheds[0][2];
let price = newScheds.splice(0, 1)[0][1]; //cut the array one-by-one
let timespec = "0 0 " + hour + " * * *";
//looping through existing schedulers
for (let k = 0; k < listScheds.length; k++) {
let t = listScheds[k].timespec;
let p = listScheds[k].calls[0].params;
//check if the scheduler exist
if (p.id === s.relayID && t.split(" ").join("") === timespec.split(" ").join("")) {
print(_.pId, "#" + ctPeriod, "Skipping scheduler at: ", hour + ":00 for relay:", s.relayID, " as it is already exist.");
isExist = true;
break;
}
}
// only create unique schedulers
if (!isExist) {
_.cntr++;
Shelly.call("Schedule.Create", {
"id": 0, "enable": true, "timespec": timespec,
"calls": [{
"method": "Switch.Set",
"params": {
"id": s.relayID,
"on": !s.isOutputInverted
}
}]
},
function (res, err, msg, data) {
if (err !== 0) {
print(_.pId, "#" + data.ctPeriod, "Scheduler at: ", data.hour + ":00 price: ", data.price, " EUR/MWh (energy price + transmission). FAILED, 20 schedulers is the Shelly limit.");
}
else {
print(_.pId, "#" + data.ctPeriod, "Scheduler starts at: ", data.hour + ":00 price: ", data.price, " EUR/MWh (energy price + transmission). ID:", res.id, " SUCCESS");
_.schedId.push(res.id); //create an array of scheduleIDs
}
_.cntr--;
},
{ hour: hour, price: price, ctPeriod: ctPeriod }
);
}
}
}
//if there are more calls in the queue
if (newScheds.length > 0) {
Timer.set(
1000, //the delay
false,
function () {
createScheds(listScheds, newScheds);
});
}
else {
setKVS();
}
}
/**
Storing the scheduler IDs in KVS to not loose them in case of power outage
*/
function setKVS() {
//wait until all the schedulerIDs are collected
if (_.cntr !== 0) {
Timer.set(
1000,
false,
function () {
setKVS();
});
return;
}
//schedulers are created, store the IDs to KVS
Shelly.call("KVS.set", { key: "version" + _.sId, value: _.version });
Shelly.call("KVS.set", { key: "timestamp" + _.sId, value: new Date().toString() });
Shelly.call("KVS.set", { key: "schedulerIDs" + _.sId, value: JSON.stringify(_.schedId) },
function () {
print(_.pId, "Script v", _.version, " created all the schedules, next heating calculation at", nextChkHr() + ":00.");
_.loopRunning = false;
});
_.schedId = [];
}
/**
Set countdown timer to flip Shelly status
*/
function setShellyTimer(isOutInv, timerMin) {
let is_on = isOutInv ? "on" : "off";
let timerSec = timerMin * 60; //time in seconds
print(_.pId, "Set Shelly auto " + is_on + " timer for ", timerMin, " minutes.");
Shelly.call("Switch.SetConfig", {
"id": 0,
config: {
"name": "Switch0",
"auto_on": isOutInv,
"auto_on_delay": timerSec,
"auto_off": !isOutInv,
"auto_off_delay": timerSec
}
});
}
// Shelly doesnt support Javascript sort function so this basic math algorithm will do the sorting job
function sort(array, sortby) {
// Sorting array from smallest to larger
let i, j, k, min, max, min_indx, max_indx, tmp;
j = array.length - 1;
for (i = 0; i < j; i++) {
min = max = array[i][sortby];
min_indx = max_indx = i;
for (k = i; k <= j; k++) {
if (array[k][sortby] > max) {
max = array[k][sortby];
max_indx = k;
}
else if (array[k][sortby] < min) {
min = array[k][sortby];
min_indx = k;
}
}
tmp = array[i];
array.splice(i, 1, array[min_indx]);
array.splice(min_indx, 1, tmp);
if (array[min_indx][sortby] === max) {
tmp = array[j];
array.splice(j, 1, array[min_indx]);
array.splice(min_indx, 1, tmp);
}
else {
tmp = array[j];
array.splice(j, 1, array[max_indx]);
array.splice(max_indx, 1, tmp);
}
j--;
}
return array;
}
function epoch() {
return Math.floor(Date.now() / 1000.0);
}
/* Next hour for heating calculation */
function nextChkHr() {
let chkT = s.heatingMode.isFcstUsed ? s.heatingMode.timePeriod : 24;
let hr = (Math.ceil((new Date().getHours() + 1) / chkT) * chkT) - 1;
return hr > 23 ? 23 : hr;
}
/**
Getting prices or forecast for today if
* prices or forecast have never been fetched OR
* prices or forecast are not from today or yesterday OR
* prices or forecast needs regular update
*/
function isUpdtReq(ts) {
let nextHour = nextChkHr();
let now = new Date();
let yestDt = new Date(now - _.dayInSec * 1000);
let tsDt = new Date(ts * 1000);
let isToday = tsDt.getFullYear() === now.getFullYear() && tsDt.getMonth() === now.getMonth() && tsDt.getDate() === now.getDate();
let isYesterday = tsDt.getFullYear() === yestDt.getFullYear() && tsDt.getMonth() === yestDt.getMonth() && tsDt.getDate() === yestDt.getDate();
let isTsAfterChkT = new Date(ts * 1000).getHours() === nextHour;
let isChkT = now.getHours() === nextHour;
return (isChkT && !isTsAfterChkT) || !(isToday || isYesterday);
}
/**
This loop runs in every xx seconds
*/
function loop() {
if (_.loopRunning) {
return;
}
_.loopRunning = true;
if (isUpdtReq(_.tsPrices) || (s.heatingMode.isFcstUsed && isUpdtReq(_.tsFcst))) {
start();
} else {
_.loopRunning = false;
}
}
Timer.set(_.loopFreq * 1000, true, loop);
/* --------- WATCHDOG START --------- */
/** This is the watchdog script code */
let watchdog = 'let _={sId:0,mc:3,ct:0};function start(e){Shelly.call("KVS.Get",{key:"schedulerIDs"+e},(function(e,l,t,c){if(e){let l=[];l=JSON.parse(e.value),e=null,delSc(l,c.sId)}}),{sId:e})}function delSc(e,l){if(_.ct<6-_.mc)for(let t=0;t<_.mc&&t<e.length;t++){let t=e.splice(0,1)[0];_.ct++,Shelly.call("Schedule.Delete",{id:t},(function(e,t,c,i){0!==t?print("Script #"+l,"schedule ",i.id," del FAIL."):print("Script #"+l,"schedule ",i.id," del OK."),_.ct--}),{id:t})}e.length>0?Timer.set(1e3,!1,(function(){delSc(e,l)})):delKVS(l)}function delKVS(e){0===_.ct?(Shelly.call("KVS.Delete",{key:"schedulerIDs"+e}),Shelly.call("KVS.Delete",{key:"version"+e}),Shelly.call("KVS.Delete",{key:"timestamp"+e}),print("Heating script #"+e,"is clean")):Timer.set(1e3,!1,(function(){delKVS(e)}))}Shelly.addStatusHandler((function(e){"script"!==e.name||e.delta.running||(_.sId=e.delta.id,start(_.sId))}));'
/** find watchdog script ID */
function createWatchdog() {
Shelly.call('Script.List', null, function (res, err, msg, data) {
if (res) {
let wdId = 0;
let s = res.scripts;
res = null;
for (let i = 0; i < s.length; i++) {
if (s[i].name === "watchdog") {
wdId = s[i].id;
break;
}
}
createScript(wdId);
}
});
}
/** Create a new script (id==0) or stop the existing script (id<>0) if watchdog found. */
function createScript(id) {
if (id === 0) {
Shelly.call('Script.Create', { name: "watchdog" }, putCode, { id: id });
}
else {
Shelly.call('Script.Stop', { id: id }, putCode, { id: id });
}
}
/** Add code to the watchdog script */
function putCode(res, err, msg, data) {
if (err === 0) {
print(_.pId, "Watchdog script has been created.");
let scId = res.id > 0 ? res.id : data.id;
Shelly.call('Script.PutCode', { id: scId, code: watchdog }, startScript, { id: scId });
}
else {
print(_.pId, "Watchdog script creation failed.", msg, ". Schedules are not deleted if heating script is stopped or deleted.");
}
}
/** Enable autostart and start the watchdog script */
function startScript(res, err, msg, data) {
if (err === 0) {
print(_.pId, "Insert code to watchdog script completed.");
if (!Shelly.getComponentConfig("script", data.id).enable) {
Shelly.call('Script.SetConfig', { id: data.id, config: { enable: true } },
function (res, err, msg, data) {
if (err != 0) {
print(_.pId, "Watchdog script autostart is not enabled.", msg, ". After Shelly restart, this script will not start and schedules are not deleted if heating script is stopped or deleted.");
}
});
}
Shelly.call('Script.Start', { id: data.id }, function (res, err, msg, data) {
if (err === 0) {
print(_.pId, "Watchdog script started succesfully.");
}
else {
print(_.pId, "Watchdog script is not started.", msg, ". Schedules are not deleted if heating script is stopped or deleted.");
}
});
}
else {
print(_.pId, "Adding code to the script is failed.", msg, ". Schedules are not deleted if heating script is stopped or deleted.")
}
}
/* --------- WATCHDOG END --------- */
createWatchdog();
loop(); |
|
|
tagasi üles |
|
 |
Level
HV veteran
liitunud: 06.03.2003
|
14.08.2024 22:01:35
|
|
|
Tere. Kuna paigaldasin remondi käigus juba sonoffi niiskusandurid , siis mõtlesin , et ka põrandaküte võiks olla samas süsteemis ja nutikuse võimalusega. Kuna Sonoffil paistab, et neid termostaate seinale peaaegu pole(erinevalt tuyast). Siis mõtlesin kas Sonoff EliTite 316D temp. Controller+Sonoff WTS01 Veekindel Temperatuurisensor saaksid elektrikütte juhtimisega hakkama? Vannitoas kaabel ja muudes ruumides põrandal küttekile
_________________ www.ohutuspartner.ee Teie partner ohutusalal
viimati muutis Level 14.08.2024 23:39:42, muudetud 1 kord |
|
tagasi üles |
|
 |
RassK
HV Guru

liitunud: 17.01.2007
|
14.08.2024 23:36:03
|
|
|
Puhtalt küll minu mõtlemine aga küttesüsteemid võiks olla võimalikult standardsed, et vajadusel saab kontrollerit igal hetkel vahetada. Igasugu spets nutijunnid ei pruugi pooltki põranda elueast vastu pidada. Standardiga on see teema, et sinna leidub iga hetk nii vanemat kui uuemat kraami.
Ehk siis ikka NTC 10k põrandasse ja seinale toos. Ise kasutan Heatit Z-TRM3, enne seda oli tavaline Heber HT115. Kõige enam hoiaks eemale igasugu pilves istuvatest jubinatest.
|
|
tagasi üles |
|
 |
Janis
HV Guru
liitunud: 30.11.2005
|
15.08.2024 00:48:37
|
|
|
See ongi suht standardne lahendus el põrandaküttele, nii seda juhitakse
|
|
tagasi üles |
|
 |
RassK
HV Guru

liitunud: 17.01.2007
|
15.08.2024 10:23:46
|
|
|
Jaa see andur on küll väga "standard", iga suvaline termostaat oskab endale sellise külge võtta
Teisest küljest kui kõik kilpi mahub ja on mahavõetav ning asendatav mitte nutika süsteemiga, siis pole suuremat vahet. Samas jälle kilpi tubasteks termostaatideks ei konverteeri.
|
|
tagasi üles |
|
 |
Janis
HV Guru
liitunud: 30.11.2005
|
15.08.2024 10:49:20
|
|
|
Anduri diameeter sama ja kõrisse läheb ilusti, väliselt ka identne meenub, mu jaoks piisavalt standard
Tuppa polegi mingit termostaati vaja kui põranda tempiga juhtida. Kui õhutempiga tahta, siis võib suvaline juhtmevaba andur samas ruumis vedeleda. Endal samasugune setup tulemas, ei pea mingit paneeli kuskile toppima hakkama
|
|
tagasi üles |
|
 |
RassK
HV Guru

liitunud: 17.01.2007
|
15.08.2024 11:28:01
|
|
|
Kui tead, et kõrisse läheb ilusti on hea. Mina pole ühegi oma uue elupinna valmistamise juures olnud, seega selle anduri tõmban sealt ainult viimases hädas
|
|
tagasi üles |
|
 |
Level
HV veteran
liitunud: 06.03.2003
|
15.08.2024 12:14:15
|
|
|
Ma tegelikult mõtlesin juurde lisada selle SONOFF NSpaneli, siis saab neid nutikaid andureid ka lokaalselt ilma neti või telefonita juhtida. nagu rumalaid andureid. tahtsin lihtsalt enne veenduda kas see andur põmst saab nende asjade sisse välja lülitamiste ja temp. hoidmisega hakkama
_________________ www.ohutuspartner.ee Teie partner ohutusalal |
|
tagasi üles |
|
 |
Janis
HV Guru
liitunud: 30.11.2005
|
15.08.2024 12:20:39
|
|
|
Tegelt pole seal väga midagi juhtida. Tal nupp ka peal ja kui saad norm kohta paigutada, siis vajadusel võib sealt manuaalselt lülitada
Mul endal need akupaagi el kütet lülitamas, boileri el kütet ja boileri soojusvaheti pumpa lülitamas. Vahel lülitan otse sonoffi pealt ka nupust.
|
|
tagasi üles |
|
 |
Level
HV veteran
liitunud: 06.03.2003
|
15.08.2024 13:00:27
|
|
|
paneeli mõte oleks sellisel juhul, et saaks vajadus lihtsamini 5te eri tsooni seadistada
_________________ www.ohutuspartner.ee Teie partner ohutusalal |
|
tagasi üles |
|
 |
RassK
HV Guru

liitunud: 17.01.2007
|
24.08.2024 00:23:22
|
|
|
Sain ka lõpuks oma ekraani seinale, seisis 3 kuud kapis kuniks piisavalt kipsitöödeks aega tekkis. Imelikul kombel oli selleks ajaks RPi sd kaardiga midagi juhtunud ja Ubuntu Server enam üles ei tulnud. Boonusena oli Ubuntu Core (IoT jaoks spets image) tulnud selle ajaga RPi 5 jaoks välja. Reflashisin sd kaardi sellega, kioski jaoks 3 käsklust ja jooksis uuesti. Hiljem võtsin siiski siitsamast foorumist nvme hati koos nvme endaga, et edaspidi see sd kaart jamasid ei põhjustaks.
Ühesõnaga õnnestus lõpuks kõik soovitu, clean look, peidetud juhtmed ning pole ka nähtavat vahet ekraani ja seina vahel. Läbi seina jookseb HDMI, USB-C ja Power, ehk siis ühenda mida iganes sinna külge vaja.
|
|
tagasi üles |
|
 |
kotik001
HV vaatleja
liitunud: 27.08.2022
|
25.08.2024 23:34:15
|
|
|
Ise käin hetkel sama teed, et riiuli pealt seinale kolida. Õnneks saan esikust suht tuimalt läbi seina puurida ja seal vajadusel möllata, kuna teisel pool on tehnoruum aka kamorka.
Üks küsimus ka. Kas keegi on mingi bussigraafiku laadse toote tööle saanud, a'la "sinu buss lahkub 5 minuti pärast"?
GTFS integratsioonile söötsin data enda arust sisse, kuid status Unknown.
Edit: gtfs2 addon hetkel annab lootust - proovin.
Edit2: Tundub, et sain tööle. Homme selge peaga veel pulli pärast uurida, kas mingi realtime data ka kätte saab.
viimati muutis kotik001 27.08.2024 00:34:46, muudetud 1 kord |
|
tagasi üles |
|
 |
Level
HV veteran
liitunud: 06.03.2003
|
26.08.2024 10:41:16
|
|
|
Uurin, kas on võimalik kuidagi kasutada ilmatedet käskude loomisel(sonoff). Sooviks nt , et muidu teatud aegadel töötav ventilaator vihma korral ei hakkaks tööle.
_________________ www.ohutuspartner.ee Teie partner ohutusalal |
|
tagasi üles |
|
 |
filx
HV kasutaja

liitunud: 12.09.2006
|
27.08.2024 15:43:22
|
|
|
Ikka on weather integrartsioonist võtad trigggeri ja conditioni ja edastad sonoffile.
_________________ Think positive!
Viljar Bauman
👨👩👧👦 father;🧙security wizard;👨🔬life engineer;👫 socialist |
|
tagasi üles |
|
 |
Level
HV veteran
liitunud: 06.03.2003
|
28.08.2024 20:43:21
|
|
|
filx kirjutas: |
Ikka on weather integrartsioonist võtad trigggeri ja conditioni ja edastad sonoffile. |
See siis vajab mingit teist rakendust mitte ewelink
_________________ www.ohutuspartner.ee Teie partner ohutusalal |
|
tagasi üles |
|
 |
filx
HV kasutaja

liitunud: 12.09.2006
|
28.08.2024 23:23:58
|
|
|
Tootjate enda rakendused on väga piiratud jah. Ma viitasin homeassitantile.
_________________ Think positive!
Viljar Bauman
👨👩👧👦 father;🧙security wizard;👨🔬life engineer;👫 socialist |
|
tagasi üles |
|
 |
Level
HV veteran
liitunud: 06.03.2003
|
29.08.2024 15:19:17
|
|
|
filx kirjutas: |
Tootjate enda rakendused on väga piiratud jah. Ma viitasin homeassitantile. |
selle jälle pole normaaselt(loe tasuta) pilvevõimalust
vatan kas Google Homega saaks midagi kompunnida või samsungi mutirakedusega
_________________ www.ohutuspartner.ee Teie partner ohutusalal |
|
tagasi üles |
|
 |
Janis
HV Guru
liitunud: 30.11.2005
|
29.08.2024 15:32:26
|
|
|
On ju? Või mida sellega mõtled? Väljast saab ligi ilusti tasuta
|
|
tagasi üles |
|
 |
RassK
HV Guru

liitunud: 17.01.2007
|
29.08.2024 16:23:17
|
|
|
Wireguard, Duckdns, HA, Nginx Proxy Manager kõik on tasuta, et luua turvaline ühendus tagasi. Kõiki ei pea neist kasutama aga saab luua erineva turvalisusega kombinatsioone.
Kui cloudi eest maksta ei taha, siis tuleb seda lõivu mujalt võtta (ehk siis enda skilli näol).
|
|
tagasi üles |
|
 |
Markos
HV veteran
liitunud: 10.04.2002
|
29.08.2024 17:10:04
|
|
|
Ma küll liigun varsti Nabucasa peale ära, siiber neist "tasuta" asjadest. Lisaks toetab see HA arendust.
|
|
tagasi üles |
|
 |
RassK
HV Guru

liitunud: 17.01.2007
|
29.08.2024 17:25:07
|
|
|
Mul 1 instance on Nabucasa peal ja teine WG taga. Nabu peal super palju just eeliseid ei ole, pigem rohkem arenduse toetamine.
|
|
tagasi üles |
|
 |
Level
HV veteran
liitunud: 06.03.2003
|
29.08.2024 20:59:16
|
|
|
RassK kirjutas: |
Wireguard, Duckdns, HA, Nginx Proxy Manager kõik on tasuta, et luua turvaline ühendus tagasi. Kõiki ei pea neist kasutama aga saab luua erineva turvalisusega kombinatsioone.
Kui cloudi eest maksta ei taha, siis tuleb seda lõivu mujalt võtta (ehk siis enda skilli näol). |
Nii on et saab, aga siis on vaja lisavidinat nt Rasberry näol. Selle olen läbi teinud juba 😀
_________________ www.ohutuspartner.ee Teie partner ohutusalal |
|
tagasi üles |
|
 |
Markos
HV veteran
liitunud: 10.04.2002
|
29.08.2024 22:18:48
|
|
|
RassK kirjutas: |
Mul 1 instance on Nabucasa peal ja teine WG taga. Nabu peal super palju just eeliseid ei ole, pigem rohkem arenduse toetamine. |
Nabu eelis on see, et ta on lihtne kasutada. Sul ei ole vaja jännata domeeninime, duckdns'i ja portforwardiga. WG ei ole korraliku presence detectioni jaoks kasututatav, sa pead tunnelit koguaeg püsti hoidma, kui tahad, et see töötaks.
tsitaat: |
Nii on et saab, aga siis on vaja lisavidinat nt Rasberry näol. Selle olen läbi teinud juba 😀 |
Ei miks ? Sa saad nimetatud asjad, nagu wireguard, cloudflare või nginx-manager kõik addonidena ha'sse panna.
|
|
tagasi üles |
|
 |
RassK
HV Guru

liitunud: 17.01.2007
|
29.08.2024 22:26:04
|
|
|
Markos kirjutas: |
RassK kirjutas: |
Mul 1 instance on Nabucasa peal ja teine WG taga. Nabu peal super palju just eeliseid ei ole, pigem rohkem arenduse toetamine. |
Nabu eelis on see, et ta on lihtne kasutada. Sul ei ole vaja jännata domeeninime, duckdns'i ja portforwardiga. WG ei ole korraliku presence detectioni jaoks kasututatav, sa pead tunnelit koguaeg püsti hoidma, kui tahad, et see töötaks.
|
Täpselt nii on. Presence detectioni võib muidu muu peale ka ringi teha, nt Mikrotikil on oma integratsioon ja jälgib kõiki IP seadmeid (olemasolu).
Markos kirjutas: |
Ei miks ? Sa saad nimetatud asjad, nagu wireguard, cloudflare või nginx-manager kõik addonidena ha'sse panna. |
See õnnetu RPi vast väga õnnelik selle üle ei ole, NUC vms vähe etem valik.
|
|
tagasi üles |
|
 |
|
lisa lemmikuks |
|
|
sa ei või postitada uusi teemasid siia foorumisse sa ei või vastata selle foorumi teemadele sa ei või muuta oma postitusi selles foorumis sa ei või kustutada oma postitusi selles foorumis sa ei või vastata küsitlustele selles foorumis sa ei saa lisada manuseid selles foorumis sa võid manuseid alla laadida selles foorumis
|
|
Hinnavaatlus ei vastuta foorumis tehtud postituste eest.
|