SmurfnSurf Posted October 7 Share Posted October 7 (edited) Hi, Pretty new to all this and pretty overwhelmed TBH, just need some high level pointers to start off with (but feel free to throw some suggested code at me too!). Pointing to the documentation is fine, but if you do so, could you point to the specific area(s) of it I should look at it please, rather than the whole lot, thanks! So I have got a Shelly Button 1, with a simple URL link (placed via the App menu) to a Central Heating (CH) Shelly mini 3G relay, to turn it on (or off) based on a one or two button click, that works fine. http://192.168.47.127/relay/0?turn=on or http://192.168.47.127/relay/0?turn=off I have also got a script (function actually) made with a great deal of help from someone else, that turns on or off the 3 "ON" schedules of a Daily Set of 3# ON/OFF Windows (for the Central Heating). The function is on the Shelly that has the Schedules on it. I added a link to this function as second URL of the Shelly Button 1 press and this also works fine, turning off the CH Schedule (so if I just turn off the relay it does not turn back on again 2 minutes later, using the schedule). This is all done natively in the Shelly ecosystem. What I would like to develop, is a simple "If Then Else" logic, such that if I turn the schedule (only) back on, IF the current time lies WITHIN one of the three time windows, it turns the CH relay on; if not, then not. After that the schedule takes over as normal. So I believe the logic is simply: If Window1Start < "TIMENOW" < Window1End OR Window2Start < "TIMENOW" < Window2End OR Window3Start < "TIMENOW" < Window3End, THEN Turn CH Auto Relay = ON OTHERWISE No Action So, what I believe I need to do is this (but please correct me): a. Mine the Schedule for the Start and End Times of the 3 Daily Time Windows and get the 6# Constants WindowXStartX and WindowXEnd, where X =1,2, and 3. I believe http://192.168.47.127/rpc/Schedule.List provides the schedule (see output below) I assume I can get the time from this output for each pair of IDs, (ID3-ID5, ID6-ID8, ID9-ID12) but I am not sure which is the best mechanism for extracting the variables? Should I use a Function (on the Shelly itself) or use a Script or a Template? { "jobs": [ { "id": 2, "enable": true, "timespec": "0 30 6 * * 0,1,2,3,4,5,6", "calls": [ { "method": "switch.set", "params": { "id": 0, "on": true } } ] }, { "id": 3, "enable": true, "timespec": "0 30 8 * * 0,1,2,3,4,5,6", "calls": [ { "method": "switch.set", "params": { "id": 0, "on": false } } ] }, { "id": 5, "enable": true, "timespec": "0 0 12 * * 0,1,2,3,4,5,6", "calls": [ { "method": "switch.set", "params": { "id": 0, "on": true } } ] }, { "id": 6, "enable": true, "timespec": "0 30 13 * * 0,1,2,3,4,5,6", "calls": [ { "method": "switch.set", "params": { "id": 0, "on": false } } ] }, { "id": 8, "enable": true, "timespec": "0 30 15 * * 0,1,2,3,4,5,6", "calls": [ { "method": "switch.set", "params": { "id": 0, "on": true } } ] }, { "id": 9, "enable": true, "timespec": "0 0 21 * * 0,1,2,3,4,5,6", "calls": [ { "method": "switch.set", "params": { "id": 0, "on": false } } ] }, { "id": 12, "enable": true, "timespec": "0 0 0 * * 0,1,2,3,4,5,6", "calls": [ { "method": "Shelly.Update", "params": { "stage": "stable" }, "origin": "shelly_service" } ] }, { "id": 13, "enable": true, "timespec": "0 0 23 * * 0,1,2,3,4,5,6", "calls": [ { "method": "switch.set", "params": { "on": false, "id": 0 } } ] } ], "rev": 402 } I started looking at this example from the Shelly folks, but it's pretty daunting. b. Next, to run the IF-THEN-ELSE- statements, should I write this in a "Template" which evaluates the IF/Then logic above to True or False, If True then Turn the Relay On (and the Schedules). If not a Template then, what is the suggested mechanism please? If anyone has some starting code examples or code library, I can play around with it. Thank you! k. Edited October 9 by SmurfnSurf Proper formatting of Schedule.List 1 Quote Translate Revert translation? English (American) Finnish French German Italian Portuguese (European) Spanish Link to comment Share on other sites More sharing options...
If_then_else Posted October 8 Share Posted October 8 @SmurfnSurf Below you will find a code sample which should meet your functional specification. /// Switch between different times V1.0 //////////////////////////////////////////////////////////////////////////////////////////// /// /// Created by "If then else" © 2024 /// //////////////////////////////////////////////////////////////////////////////////////////// function timerHandler() { // create a new Date object let now = new Date(); // get the current hour (from 0 to 23) let hour = now.getHours(); // get the current minute (from 0 to 59) let minute = now.getMinutes(); // get the current minutes of the actual day actdayminutes = (hour * 60) + minute; /// if ( ((actdayminutes >= (09 * 60) + 00) && (actdayminutes < (11 * 60) + 00)) /// (time greater than 9:00) AND (time less than 11:00) || ((actdayminutes >= (13 * 60) + 00) && (actdayminutes < (15 * 60) + 00)) /// (time greater than 13:00) AND (time less than 15:00) || ((actdayminutes >= (15 * 60) + 00) && (actdayminutes < (17 * 60) + 00))) { /// (time greater than 15:00) AND (time less than 17:00) // print('Time window activ'); // } else { // print('Time window not activ'); // }; }; //////////////////////////////////////////////////////////////////////////////////////////// Timer.set(1000, true, timerHandler, null); //////////////////////////////////////////////////////////////////////////////////////////// 1 Quote Translate Revert translation? English (American) Finnish French German Italian Portuguese (European) Spanish Link to comment Share on other sites More sharing options...
SmurfnSurf Posted October 9 Author Share Posted October 9 Wow thank you, that is awesome (love your username btw, very apt!). I will see how I can integrate this into the CH system relay and let you know how I’m doing. If the times could be mined from the schedule ID so they were dynamic that would be a really nice enhancement. Thank you once again! k. Quote Translate Revert translation? English (American) Finnish French German Italian Portuguese (European) Spanish Link to comment Share on other sites More sharing options...
SmurfnSurf Posted Monday at 02:27 Author Share Posted Monday at 02:27 (edited) On 10/9/2024 at 12:13 AM, If_then_else said: @SmurfnSurf Below you will find a code sample which should meet your functional specification. Hi me again, OK I have spent some time trying to see whether I could possibly write any part of a script using what I have gleaned from your script (thank you again) and other scripts I have seen, so you don't think I am just expecting it to just be done for me, but that I have tried to work it out :-). I believe here, in your function (correct me if I am wrong, very newbie like especially with this syntax..): the timerHandler function is entirely bound by the first set of curly brackets {} the result of the 3 'if' lines being true i.e. print('Time window active') is within the second set of curly brackets {} i.e. 'then'; and the 'else' is just by default "not active" and is within the third set of curly brackets {}. timer.set 'arms' the timer, but I am not 100% sure what that means. 1000ms is 1s so I assume that it "x" (see below), while 'true' means it will repeat and 'timerhandler' is the function that repeats? Some questions please, if I may, to use it to actually enable a switch: Could the times be extracted from a set of fixed (stated) schedule IDs rather than a fixed value? Could the period 'x' be increased (assuming this is the 1000ms?) Could I just run it (timeHandler) for only as long as it takes to confirm the period is "active" then turn on a relay and then STOP running the function (until the next time the function was called) so it does not run constantly? For (3), the reason for this request (and indeed the timer) is that I have a function (kindly provided by @towiat here) which helps me switch on or off (see pic) the schedules running a CH relay. The function is below FYI. Essentially (from a Shelly Button 1), I turn off the Manual Button (A) even if it is off, I turn in the Auto Schedule (B) and I start (unnecessarily) the Relay that switches the CH ON. A. http://192.168.47.128/relay/0?turn=off B. http://192.168.47.127/rpc/Script.Eval?id=3&code=switchSchedules(true) C. http://192.168.47.127/relay/0?turn=on When I switch the schedules on (B), there are two states, either the schedule SHOULD BE running as it is in a Schedule ON Window or it should not. However so that it is not freezing cold for a long period until the next ON Window, I currently just switch it ON (C) anyway, to be sure. This means however that it might be ON (unnecessarily) for a long time, just wasting power (Diesel actually), when the schedule would normally have it OFF. Whether this could (should?) run from within function switchSchedules() or whether it should be an independent function that calls your function timerHandler() or runs from within it, I am not sure which is the best approach? So, assuming the schedules have been turned on (B), I am looking for a function that (I can replace (C) with) that: First, STARTs your function timeHandler // i.e. it does not need to be running all the time right? (Preferably) allows function timeHandler to use the IDs from function switchSchedules (or just uses IDs that I put in the function) and checks whether the timer window "is active" or is "not active" based on the start and stop times for each set of IDs. If timer window "is active" then issues http://192.168.47.127/relay/0?turn=on to start the relay // needs amending of function timerHandler() so that it assigns a variable to "is active" e.g. UNDER "print('Time window active')", just add a line let tH=1 say? STOPs function timeHandler, so it does nor use CPU cycles unnecessarily, as it only needs to know it for a brief (almost instantaneous) period, the Auto schedule will take care of the rest. So, having a go at this myself (excuse the crude attempt!) , something like this, called by C. http://192.168.47.127/rpc/Script.Eval?id=3&code=turnonAutoinWindow function turnonAutoinWindow() // name of my new function that replace the C line in Shelly Button 1 Script.Start?id=2 // START function timerHandler() using Start and End Times from ID= X, ID=Y, ID=Z// call AND start the timerHandler function if tH=1 { http://192.168.47.127/relay/0?turn=on } else { Script.Stop?id=2 // STOP function timerHandler() } FYI: This is the function from @towiat function switchSchedules(value) { let schedules = [2, 5, 8]; // <-- example: change only the 1st, 3rd, 6th and 7th schedule Shelly.call("Schedule.List", {}, function (result) { for (let job of result.jobs) { if (schedules.indexOf(job.id) !== -1) { job.enable = value; Shelly.call("Schedule.Update", job); } } }); } Edited Monday at 03:06 by SmurfnSurf clarity Quote Translate Revert translation? English (American) Finnish French German Italian Portuguese (European) Spanish Link to comment Share on other sites More sharing options...
If_then_else Posted Monday at 12:33 Share Posted Monday at 12:33 (edited) @SmurfnSurf I would like to set a few facts straight. My script proposal would be created based on the specification you formulated. (See below) - I am convinced that this will also be fulfilled with my proposal. Quote What I would like to develop, is a simple "If Then Else" logic, such that if I turn the schedule (only) back on, IF the current time lies WITHIN one of the three time windows, it turns the CH relay on; if not, then not. After that the schedule takes over as normal. So I believe the logic is simply: If Window1Start < "TIMENOW" < Window1End OR Window2Start < "TIMENOW" < Window2End OR Window3Start < "TIMENOW" < Window3End, THEN Turn CH Auto Relay = ON OTHERWISE No Action So, what I believe I need to do is this (but please correct me): ------------------------------------------------------------------------------------------------------------- I can tell from your last posting that you have very limited programming experience.😉 You are mixing actions, cyclic program sequences and event-triggered functions. You are also mixing various code examples from different authors. I will therefore take myself out of this matter and would advise you to read through this Shelly documentation.{Shelly documentations} Edited Monday at 12:35 by If_then_else Quote Translate Revert translation? English (American) Finnish French German Italian Portuguese (European) Spanish Link to comment Share on other sites More sharing options...
SmurfnSurf Posted Monday at 13:11 Author Share Posted Monday at 13:11 30 minutes ago, If_then_else said: I can tell from your last posting that you have very limited programming experience. You are correct and my apologies if I’ve overstepped the mark with my request for help here. I very much appreciate the sample you posted. I appreciate that having a set of powerful instructions makes the device utilisation very powerful but I didn’t think it would be (or should be) this hard to get them to do a few simple things. I will go through the documentation as suggested but I’d imagine that I will probably end up just being daunted by it and I’d imagine I am not the first nor the last. Nonetheless, appreciate your input. Quote Translate Revert translation? English (American) Finnish French German Italian Portuguese (European) Spanish Link to comment Share on other sites More sharing options...
towiat Posted Monday at 21:27 Share Posted Monday at 21:27 Okay, I'll give this a try - in our last conversation, I answered your question about the Schedule.Update thing without a real understanding of why you need it. Your schedule-based solution is creative but also difficult to handle and I don't think that you ever had a chance of solving this completely without some coding. And I wouldn't exactly call this 'a few simple things' ;). If I understand your requirements correctly, then this problem can be solved in a much easier (well, easier for programmers ;)) way with approximately 30 lines of code and a single schedule. But before I show you a possible solution, I need to make absolutely sure that I really understand what you want to achieve. So can you read my interpretation of your requirements and tell me if it is accurate: Your Shelly should be able to control your central heating autonomously. When in that 'autonomous mode', it should BY ITSELF make sure that the heating is switched on during certain times of the day and switched off for the remaining time. In your current setup, it should be switched on from 06:30 to 08:30, 12:00 to 13:30 and 15:30 to 21:00, but you may need different/more/fewer time windows in the future. You want the ability to disable the autonomous mode at will by sending an HTTP request. When the autonomous mode is disabled, the Shelly should do nothing by itself, but you should be able to manually turn heating on or off (again with HTTP requests). You also want the ability to re-enable autonomous mode with an HTTP request. When you do that, the Shelly should immediately resume the logic that is described in #1. Is this somewhat close or did I get it wrong or miss something? 1 Quote Translate Revert translation? English (American) Finnish French German Italian Portuguese (European) Spanish Link to comment Share on other sites More sharing options...
SmurfnSurf Posted 23 hours ago Author Share Posted 23 hours ago (edited) 3 hours ago, towiat said: Okay, I'll give this a try - in our last conversation, I answered your question about the Schedule.Update thing without a real understanding of why you need it. Your schedule-based solution is creative but also difficult to handle and I don't think that you ever had a chance of solving this completely without some coding. And I wouldn't exactly call this 'a few simple things' ;). If I understand your requirements correctly, then this problem can be solved in a much easier (well, easier for programmers ;)) way with approximately 30 lines of code and a single schedule. But before I show you a possible solution, I need to make absolutely sure that I really understand what you want to achieve. So can you read my interpretation of your requirements and tell me if it is accurate: Your Shelly should be able to control your central heating autonomously. When in that 'autonomous mode', it should BY ITSELF make sure that the heating is switched on during certain times of the day and switched off for the remaining time. In your current setup, it should be switched on from 06:30 to 08:30, 12:00 to 13:30 and 15:30 to 21:00, but you may need different/more/fewer time windows in the future. You want the ability to disable the autonomous mode at will by sending an HTTP request. When the autonomous mode is disabled, the Shelly should do nothing by itself, but you should be able to manually turn heating on or off (again with HTTP requests). You also want the ability to re-enable autonomous mode with an HTTP request. When you do that, the Shelly should immediately resume the logic that is described in #1. Is this somewhat close or did I get it wrong or miss something? Thank you (and genuinely no disrespect to @If_then_else here). Yes I believe you have it well-described in your points 1 to 3, but perhaps let me give you some further background so it makes sense. My parents have a Diesel boiler that runs the Central Heating. It was controlled by an (equivalent) Honeywell ST-6400C timer in which you can set 3 (and only 3) on-ff time windows a day. It had a slide switch where you could either (a) turn it off completely (OFF) (b) have it on the timer (AUTO) (c) run it continuously (MANUAL) or (d) run it once (ONCE), a feature we do not need and do not use. We had the Controller replaced with 2# Shelly Switches (Relays), one for the AUTO mode and one for the MANUAL. I appreciate we could probably have used one relay but it would have got too complicated, so we decided to try to emulate the slide switch (and provide some redundancy) with two switches. The AUTO Switch is controlled by a Shelly Button 1 (a white one). Its IP address is 192.168.47.127 The MANUAL Switch is controlled by a separate Shelly Button 1 (a black one). Its IP address is 192.168.47.128. The actions of each Button are shown in the pictures attached and in the Table below. My brother and I decided utilising two separate Buttons was the easiest way to emulate the previous controller and we purposely shied away from more than two sets of button-presses per button. We also decided turning both OFF when folks are away for an extended period was a reasonable compromise to emulate the slide switch off; and we can see the relays go off in the App just to be sure. One point to note is that the Auto-on mode or manual-off Mode (switchSchedules(true)) turns ON the Diesel Boiler EVEN IF the time(now) is outside the (Auto) Time WIndow in which they would ordinarily run. This happens in two scenarios, at either Auto On or Manual Off (and wastes fuel unnecessarily). Shelly Button 1 URLs Auto On (turn off Manual SW; turn on Auto Schedules; turn on Auto SW*) - WHITE BUTTON http://192.168.47.128/relay/0?turn=off http://192.168.47.127/rpc/Script.Eval?id=3&code=switchSchedules(true) http://192.168.47.127/relay/0?turn=on * If the schedule ON time has passed (even by just a minute) unless you turn Auto Relay ON (URL 3), it will only turn on in the next window. If we also turn ON the Auto SW, and this is just a minute past when Auto would have turned it off, then it will run for hours and burn Diesel until the end of the next Window. Need to rethink this. Auto off (turn off Auto SW; turn off Auto Schedules; turn off Manual SW) - WHITE BUTTON http://192.168.47.127/relay/0?turn=off http://192.168.47.127/rpc/Script.Eval?id=3&code=switchSchedules(false) http://192.168.47.128/relay/0?turn=off Manual On (turn off Auto SW; turn off Auto Schedules; turn on Manual SW with a Short Timer) - BLACK BUTTON http://192.168.47.127/relay/0?turn=off http://192.168.47.127/rpc/Script.Eval?id=3&code=switchSchedules(false) http://192.168.47.128/relay/0?turn=on&timer=7200 7200s = 2 hours Manual off (turn off Manual SW*; turn on Auto Schedules; turn on Auto SW) - BLACK BUTTON http://192.168.47.128/relay/0?turn=off http://192.168.47.127/rpc/Script.Eval?id=3&code=switchSchedules(true) http://192.168.47.127/relay/0?turn=on See comment above re the Auto schedule and on current ON window. I believe these are what you describe as being able to enable or disable "autonomous mode with an HTTP request". As you have probably seen from my feeble attempts to make this work, my attempts so far have been all using the HTTP requests you refer to above, based on the Shelly Webhooks reference. This is something I can understand reasonably easily and get to work with trial and error. This, along with your script to disable or (re)enable schedules based on schedule IDs has enabled me to almost emulate the slide switch of the original controller (ignoring ONCE), with the exception that on the original controller, Auto would run the Boiler if you switched it to that mode WITHIN the time WIndow and would NOT run it, if it was not within that Window. My current Shelly setup does not recognise Time(Now) vs Schedule, hence the initial request in this thread, to somehow marry the two. I am quite happy with the HTTP calls, just aware (from the messages in the App) of not having too many. I was thinking about this issue again today and was wondering if If_then_else's script already identifies that you're within a time window, whether just after: print('Time window activ'); you could just write this and it would switch it on (but you'd still need some way of calling the function, maybe a fourth HTTP request, too many?). Anyway, this is where I started ot get a bit lost, sorry. http://192.168.47.127/rpc/Switch.Set?id=0&on=true My concern with the function timerHandler() was that it seemed to run continuously, which wasn't really required, only as a once-off, when you enabled the schedules (one of Auto Mode ON or Manual Mode OFF). My comment (separate post above) regarding using IDs from your function was secondary, a nice to have in case the schedules were changed in the App (but the one in the script gets forgotten). Hopefully this gives you some better understanding of what we woudl like ot do, without (hopefulyl) it becoming too complicated. Thank you for your offer of help and if it looks like it's going to be too-hard-basket, that's ok. Edited 23 hours ago by SmurfnSurf spelling, clarity Quote Translate Revert translation? English (American) Finnish French German Italian Portuguese (European) Spanish Link to comment Share on other sites More sharing options...
towiat Posted 11 hours ago Share Posted 11 hours ago Okay, that was quite the wall of text ;), but as far as I can see, the solution that I have in mind should actually work. Before we begin: This solution is completely different from yours. If you want to use it, you have to remove all the schedules that you currently have defined and you should also remove the script that provides the switchSchedules() function as it is no longer needed. Before you do anything, make sure that you have read and understood this whole thing - then, you have to decide if you want to try this. The solution has to components: A simple script that provides a function that I have named checkTime(). This function checks if the current time is within one of the time windows in which heating should be activated. If the answer is 'yes', it will make sure that the power switch is ON. If the answer is 'no', it will make sure that the power switch is OFF. One single schedule that calls checkTime() once every minute. The single schedule represents AUTO mode. When it is enabled, the regular calls to checkTime() will make sure that heating is on or off as desired. To enable it, you use a standard Schedule.Update call: http://192.168.47.127/rpc/Schedule.Update?id=1&enable=true # use your schedule id! When you disable the schedule, the regular calls to checkTime() won't happen, so you are free to switch heating on or off by other means (like your MANUAL button). Disabling the schedule also works with the standard Schedule.Update URL: http://192.168.47.127/rpc/Schedule.Update?id=1&enable=false # use your schedule id! For your buttons, this means: - The switchSchedules(true) URL must be replaced with the above enabling URL - The switchSchedules(false) URL must be replaced with the above disabling URL Since the schedule re-checks the heating status every minute, you no longer need to worry about whether you are in the time window or not after enabling AUTO mode. The checkTime() function will automatically do the right thing during its next execution (which may happen up to 60 seconds after the enabling call). And... that's it. If you want to use this, you need to install the script first. The installation routine is exactly the same as for the switchSchedules function (create script, paste code, save and start, activate 'run on startup'). This is the code that you have to copy: // list of time windows with their respective start and end hours/minutes // when auto mode is active, heating will be turned on only in these time windows // sHour + sMin define the start and eHour + eMin the end of each window // change this if you want - you can have as many windows as you need let timeWindows = [ { sHour: 6, sMin: 30, eHour: 8, eMin: 30 }, // 1st time window { sHour: 12, sMin: 0, eHour: 13, eMin: 30 }, // 2nd time window { sHour: 15, sMin: 30, eHour: 21, eMin: 0 }, // 3rd time window ]; // helper function to convert hour + minute into minute of the day function minOfDay(hour, minute) { return hour * 60 + minute; } // the schedule will call this function every full minute function checkTime() { // get the current minute let now = new Date(); let curMin = minOfDay(now.getHours(), now.getMinutes()); // check if the current minute is within one of the time windows let inTimeWindow = false; for (let win of timeWindows) { if (minOfDay(win.sHour, win.sMin) <= curMin && curMin < minOfDay(win.eHour, win.eMin)) { inTimeWindow = true; break; } } // get the current state of the power switch and flip it if needed Shelly.call("Switch.GetStatus", { id: 0 }, function (result) { if (result.output !== inTimeWindow) { Shelly.call("Switch.Set", { id: 0, on: inTimeWindow }); } }); } Note that you can change the time window definitions if you want to. Also note down the ID that the Shelly has assigned to this script as we need it in the second step. In order to create the schedule that calls checkTime() every minute, we need to use an HTTP RPC call (the Shelly user interface unfortunately lacks the functionality to create this specific schedule). First, you need modify the below URL so that it contains the correct script id - replace the number after "id": with the correct ID from the previous step. Then, invoke the URL EXACTLY ONCE in the browser. http://192.168.47.127/rpc/Schedule.Create?timespec="0 * * * * *"&calls=[{"method":"Script.Eval","params":{"id":1,"code":"checkTime()"}}] After that, you should see the created schedule on the Shelly. It may display a message "Call my not work as expected", but this is just a quirk in the Shelly firmware. The call will, in fact, work as expected. And that should be it. Let me know if you were brave enough to try it ;) and if it works as expected. 1 Quote Translate Revert translation? English (American) Finnish French German Italian Portuguese (European) Spanish Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.