UNPKG

thingzi-logic-timers

Version:

Easy to use time based nodes with clean design

392 lines (358 loc) 17.7 kB
<script type="text/javascript"> RED.nodes.registerType('thingzi-activity', { category: 'function', color: '#9ccff5', defaults: { name: {value: ''}, lat: {value: '', validate: function(v){ return latLonValidator(this,v) ; }}, lon: {value: '', validate: function(v){ return latLonValidator(this,v) ; }}, // Activity timer duration in seconds timerduration: {value: 60, required: true, validate: function(v){ return v >= 0; }}, // Activity trigger triggervaluetype: {value: 'str'}, triggervalue: {value: 'ON'}, resetvaluetype: {value: 'str'}, resetvalue: {value: null}, extendtimer: {value: true}, // ON config params ontype: {value: 'tod'}, ontimesun: {value: 'dusk'}, ontimetod: {value: null}, ontimetodtype: {value: 'str'}, onoffset: {value: null, validate: function(v){ return (v >= -180 && v <= 180); }}, onrandomoffset: {value: null}, // OFF config params offtype: {value: 'tod'}, offtimesun: {value: 'dawn'}, offtimetod: {value: null}, offtimetodtype: {value: 'str'}, offoffset: {value: null, validate: function(v){ return (v >= -180 && v <= 180); }}, offrandomoffset: {value: null}, // Days of the week mon: {value: true}, tue: {value: true}, wed: {value: true}, thu: {value: true}, fri: {value: true}, sat: {value: true}, sun: {value: true}, // Limit activity range limitactivity: {value: false}, // Pass on unchecked days passunchecked: {value: false}, }, inputs: 1, outputs: 1, outputLabels: ["activity"], icon: "activity.png", label: function () { return this.name ?? "activity"; }, paletteLabel: "activity", oneditprepare: function () { var updateGeo = function() { if ($('#node-input-limitactivity').prop("checked") && ($('#node-input-ontype').val() === 'sun' || $('#node-input-offtype').val() === 'sun')) { $('.thingzi-geo').show(); } else { $('.thingzi-geo').hide(); } } var updateLimit = function() { if ($('#node-input-limitactivity').prop("checked")) { $('.thingzi-limitactivity').show() } else { $('.thingzi-limitactivity').hide() } } // TRIGGER $("#node-input-triggervaluetype").val(this.triggervaluetype ?? 'str'); $("#node-input-triggervalue").typedInput({ default: 'str', typeField: $("#node-input-triggervaluetype"), types:['str','num','bool'] }); // RESET $("#node-input-resetvaluetype").val(this.resetvaluetype ?? 'str'); $("#node-input-resetvalue").typedInput({ default: 'str', typeField: $("#node-input-resetvaluetype"), types:['str','num','bool'] }); // START var startType = $('#node-input-ontype'); var startTimeTod = $('#node-input-ontimetod'); var startTimeTodType = $('#node-input-ontimetodtype'); if (!startType.val()) { startType.val('tod'); } if (!startTimeTodType.val()) { startTimeTodType.val('str'); } startType.on('change', function(data) { $('.thingzi-starttype').hide(); switch (startType.val()) { case "sun": $('.thingzi-starttype-sun').show(); break; case "tod": $('.thingzi-starttype-tod').show(); break; } }); startTimeTod.typedInput({ default: 'str', typeField: startTimeTodType, types:['str','flow','global']}); startTimeTodType.val(this.ontimetodtype); // END var endType = $('#node-input-offtype'); var endTimeTod = $('#node-input-offtimetod'); var endTimeTodType = $('#node-input-offtimetodtype'); if (!endType.val()) { endType.val('tod'); } if (!endTimeTodType.val()) { endTimeTodType.val('str'); } endType.on('change', function(data) { $('.thingzi-endtype').hide(); switch (endType.val()) { case "sun": $('.thingzi-endtype-sun').show(); break; case "tod": $('.thingzi-endtype-tod').show(); break; } }); endTimeTod.typedInput({ default: 'str', typeField: endTimeTodType, types:['str','flow','global']}); endTimeTodType.val(this.offtimetodtype); // Get lat/long from API if (!$("#node-input-lat").val().trim() && !$("#node-input-lon").val().trim()) { $.getJSON('thingzi/timer/location', function( data, status, xhr ) { $("#node-input-lat").val(Number(data.latitude.toFixed(5))); $("#node-input-lon").val(Number(data.longitude.toFixed(5))); }); } // Show/hide Geo fields updateGeo(); $('.thingzi-geo-check').on('change', function(data) { updateGeo(); }); // Show/hide time range updateLimit(); $('#node-input-limitactivity').on('change', function(data) { updateLimit(); updateGeo(); }); } }); var latLonValidator = function(node, v){ if (node.ontype === 'sun' || node.offtype === 'sun') { return (node.lat.length > 0 && !isNaN(node.lat) && node.lon.length > 0 && !isNaN(node.lon)); } else { return true; } } </script> <script type="text/html" data-template-name="thingzi-activity"> <div class="form-row"> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <input type="text" id="node-input-name" placeholder="name"> </div> <div class="form-row"> <label for="node-input-timerduration">Timer (secs)</label> <input type="number" id="node-input-timerduration"> </div> <div class="form-row"> <label title="if ticked and triggers occur while the timer is running, the timer is silently restarted." style="margin-left: 100px; width: 70%"> <input type="checkbox" id="node-input-extendtimer" style="width: 20px; margin: 0"> <span>Extend timer on new events</span> </label> </div> <div class="form-row"> <label title="value passed in <code>payload</code> which triggers the activity" for="node-input-triggervalue">Trigger Value</label> <input type="text" id="node-input-triggervalue" style="width:70%"> <input type="hidden" id="node-input-triggervaluetype"> </div> <div class="form-row"> <label title="value passed in <code>payload</code> which will reset the trigger" for="node-input-resetvalue">Reset Value</label> <input type="text" id="node-input-resetvalue" style="width:70%" placeholder="Leave empty for no reset"> <input type="hidden" id="node-input-resetvaluetype"> </div> <div class="form-row"> <label title="days to check, by default not ticked days will fail the check" for="node-input-lat"><i class="fa fa-calendar"> </i> Schedule </label> <table style="display: inline-block; position: relative; top: 5px; left: -5px;"> <tr> <td><input type="checkbox" id="node-input-mon" placeholder="" style="width: 20px; margin: 0">Mon</td> <td><input type="checkbox" id="node-input-tue" placeholder="" style="width: 20px; margin: 0">Tue</td> <td><input type="checkbox" id="node-input-wed" placeholder="" style="width: 20px; margin: 0">Wed</td> <td><input type="checkbox" id="node-input-thu" placeholder="" style="width: 20px; margin: 0">Thu</td> <td><input type="checkbox" id="node-input-fri" placeholder="" style="width: 20px; margin: 0">Fri</td> <td><input type="checkbox" id="node-input-sat" placeholder="" style="width: 20px; margin: 0">Sat</td> <td><input type="checkbox" id="node-input-sun" placeholder="" style="width: 20px; margin: 0">Sun</td> </tr> </table> </div> <div class="form-row"> <label title="if ticked, triggers can be limited to a specific time range e.g. night time" style="margin-left: 100px; width: 70%"> <input type="checkbox" id="node-input-limitactivity" style="width: 20px; margin: 0"> <span>Limit time range</span> </label> </div> <div class="form-row thingzi-limitactivity"> <label title="if ticked, when a day is unchecked the test will always pass" style="margin-left: 100px; width: 70%"> <input type="checkbox" id="node-input-passunchecked" style="width: 20px; margin: 0"> <span>Ignore time range on unchecked days</span> </label> </div> <div class="thingzi-limitactivity"> <hr> <h4>Start</h4> <div class="form-row"> <label for="node-input-ontype">Type</label> <select id="node-input-ontype" class="thingzi-geo-check"> <option value="tod">Time of Day</option> <option value="sun">Sun Event</option> </select> </div> <div class="form-row thingzi-starttype thingzi-starttype-sun"> <label for="node-input-ontimesun">Sun Event</label> <select id="node-input-ontimesun"> <option value="solarNoon">Solar Noon</option> <option value="goldenHourEnd">Golden Hour End</option> <option value="goldenHour">Golden Hour</option> <option value="sunriseEnd">Sunrise End</option> <option value="sunsetStart">Sunset Start</option> <option value="sunrise">Sunrise</option> <option value="sunset">Sunset</option> <option value="dawn">Dawn</option> <option value="dusk">Dusk</option> <option value="nauticalDawn">Nautical Dawn</option> <option value="nauticalDusk">Nautical Dusk</option> <option value="nightEnd">Night End</option> <option value="night">Night</option> <option value="nadir">Nadir</option> </select> </div> <div class="form-row thingzi-starttype thingzi-starttype-tod"> <label for="node-input-ontimetod" title="Simple time string e.g. HH::mm. Can also value from flow or global context"> Time (HH:mm) </label> <input type="text" id="node-input-ontimetod" style="width: 70%"/> <input type="hidden" id="node-input-ontimetodtype"> </div> <div class="form-row thingzi-starttype thingzi-starttype-sun thingzi-starttype-tod"> <label for="node-input-onoffset">Offset (mins)</label> <input type="number" id="node-input-onoffset" placeholder="0"> </div> <div class="form-row thingzi-starttype thingzi-starttype-sun thingzi-starttype-tod"> <label style="margin-left: 100px; width: 70%"> <input type="checkbox" id="node-input-onrandomoffset" placeholder="" style="width: 20px; margin: 0"> Randomise time within offset </label> </div> </div> <div class="thingzi-limitactivity"> <hr> <h4>End</h4> <div class="form-row"> <label for="node-input-offtype">Type</label> <select id="node-input-offtype" class="thingzi-geo-check"> <option value="tod">Time of Day</option> <option value="sun">Sun Event</option> </select> </div> <div class="form-row thingzi-endtype thingzi-endtype-sun"> <label for="node-input-offtimesun">Sun Event</label> <select id="node-input-offtimesun"> <option value="solarNoon">Solar Noon</option> <option value="goldenHourEnd">Golden Hour End</option> <option value="goldenHour">Golden Hour</option> <option value="sunriseEnd">Sunrise End</option> <option value="sunsetStart">Sunset Start</option> <option value="sunrise">Sunrise</option> <option value="sunset">Sunset</option> <option value="dawn">Dawn</option> <option value="dusk">Dusk</option> <option value="nauticalDawn">Nautical Dawn</option> <option value="nauticalDusk">Nautical Dusk</option> <option value="nightEnd">Night End</option> <option value="night">Night</option> <option value="nadir">Nadir</option> </select> </div> <div class="form-row thingzi-endtype thingzi-endtype-tod"> <label for="node-input-offtimetod" title="Simple time string e.g. HH::mm. Can also value from flow or global context" > Time (HH:mm) </label> <input type="text" id="node-input-offtimetod" style="width: 70%" placeholder="HH:mm"/> <input type="hidden" id="node-input-offtimetodtype"> </div> <div class="form-row thingzi-endtype thingzi-endtype-sun thingzi-endtype-tod"> <label for="node-input-offoffset">Offset (mins)</label> <input type="number" id="node-input-offoffset" placeholder="0"> </div> <div class="form-row thingzi-endtype thingzi-endtype-sun thingzi-endtype-tod"> <label style="margin-left: 100px; width: 70%"> <input type="checkbox" id="node-input-offrandomoffset" placeholder="" style="width: 20px; margin: 0"> Randomise time within offset </label> </div> </div> <div class="thingzi-geo"> <hr> <h4>Sun Events</h4> <div class="form-row"> <label for="node-input-lat"><i class="fa fa-globe"></i> Latitude</label> <input type="text" id="node-input-lat" placeholder="51.025"> </div> <div class="form-row"> <label for="node-input-lon"><i class="fa fa-globe"></i> Longitude</label> <input type="text" id="node-input-lon" placeholder="-1.4"> </div> </div> </script> <script type="text/html" data-help-name="thingzi-activity"> <p>Handle an activity event and start a timer with optional extension for new events. Useful for motion events and lighting.</p> <h3>Inputs</h3> <dl class="message-properties"> <dt class="optional">payload <span class="property-type">string</span></dt> <dd> Message that triggers the activity. Must match the value set in the node properties.</dd> <dt class="optional">disable <span class="property-type">string</span></dt> <dd> Disable the activity, even when in progress, can be <code>ON</code> or <code>OFF</code>. Useful if you need to override behaviour e.g. via a switch</dd> <dt class="optional">reset <span class="property-type">string</span></dt> <dd> Reset any active timer. Message content is ignored.</dd> <dt class="optional">starttime (optional) <span class="property-type">string</span></dt> <dd> Simple time string to use instead of the start time e.g. HH:mm. This forces "time of day" mode for the start time</dd> <dt class="optional">endtime (optional) <span class="property-type">string</span></dt> <dd> Simple time string to use instead of the off time e.g. HH:mm. This forces "time of day" mode for the end time</dd> </dl> <h3>Outputs</h3> <ol class="node-ports"> <li>Activty <dl class="message-properties"> <dt>payload <span class="property-type">string</span></dt> <dd> Activity state <code>ON</code> or <code>OFF</code></dd> </dl> </li> </ol> <h3>Details</h3> <p>Ideal for usage where motion sensors drive lights or similar. Listens for a trigger message to begin the activity. When the trigger is received ON is sent and the timer starts. When the timer ends OFF is sent.</p> <p>Optional: If "Extend timer on new events" is enabled and triggers occur while the timer is running, the timer is silently extended.</p> <p>Time ranges can optionally be used to limit activity within a specified range. e.g. "only start activity when dark". When using sun events the node will try to use your lat/long position using the IP address of your ISP which is usually close enough. You can override this if you wish.</p> <p>Times entered as text must be in 24hr format <code>HH:mm</code> (or military time in US). e.g. 18:45 or 09:50. Note that seconds are also supported e.g. 11:30:45</p> </script>