Skip to content

Commit

Permalink
feat(poll-state): Added Interval Units
Browse files Browse the repository at this point in the history
Added Interval Units and check for extra spaces around entity id
  • Loading branch information
zachowj committed Mar 8, 2019
1 parent 126f227 commit 44f75c0
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 79 deletions.
18 changes: 13 additions & 5 deletions nodes/poll-state/poll-state.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
name: { value: "" },
server: { value: "", type: "server", required: true },
updateinterval: { value: "10", validate: v => !isNaN(v) },
updateIntervalUnits: { value: "seconds" },
outputinitially: { value: false },
outputonchanged: { value: false },
entity_id: {
Expand Down Expand Up @@ -103,7 +104,9 @@
});
},
oneditsave: function() {
this.entity_id = $("#entity_id").val();
this.entity_id = $("#entity_id")
.val()
.trim();
const outputs = $("#node-input-halt_if").val() ? 2 : 1;
$("#node-input-outputs").val(outputs);
},
Expand Down Expand Up @@ -134,8 +137,13 @@
</div>

<div class="form-row">
<label for="node-input-updateinterval"><i class="fa fa-clock-o"></i> Update Interval</label>
<input type="text" id="node-input-updateinterval" placeholder="10" style="width: auto;"/> <span style="padding-left: 5px;">Seconds</span>
<label for="node-input-updateinterval"><i class="fa fa-clock-o"></i> Update Interval</label>
<input type="text" id="node-input-updateinterval" style="text-align:end; width:50px !important">
<select id="node-input-updateIntervalUnits" style="width:auto !important">
<option value="seconds">seconds</option>
<option value="minutes">minutes</option>
<option value="hours">hours</option>
</select>
</div>

<div class="form-row">
Expand Down Expand Up @@ -183,10 +191,10 @@
<h3>Config</h3>
<dl class="message-properties">
<dt>Update Interval<span class="property-type">number</span></dt>
<dd>Number of seconds between checking / sending updates</dd>
<dd>The amount of time between checking / sending updates</dd>

<dt>Half If<span class="property-type">string</span></dt>
<dd>If the new_state === this setting then skip sending</dd>
<dd>If the new state equals this value the message will be sent to the second output</dd>

<dt>State Type<span class="property-type">string</span></dt>
<dd>Convert the state of the entity to the selected type. Boolean will be convert to true based on if the string is equial by default to (y|yes|true|on|home|open). Original value stored in msg.data.original_state</dd>
Expand Down
150 changes: 76 additions & 74 deletions nodes/poll-state/poll-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module.exports = function(RED) {
config: {
entity_id: {},
updateinterval: {},
updateIntervalUnits: {},
outputinitially: {},
outputonchanged: {},
state_type: {},
Expand All @@ -19,30 +20,41 @@ module.exports = function(RED) {
class TimeSinceStateNode extends EventsNode {
constructor(nodeDefinition) {
super(nodeDefinition, RED, nodeOptions);
this.entityId = (this.nodeConfig.entity_id || '').trim();
this.init();
}

init() {
if (!this.nodeConfig.entity_id)
throw new Error('Entity ID is required');
if (!this.entityId) {
throw new Error('Entity Id is required');
}

if (!this.timer) {
const interval =
!this.nodeConfig.updateinterval ||
parseInt(this.nodeConfig.updateinterval) < 1
? 1
? 10
: parseInt(this.nodeConfig.updateinterval);

switch (this.nodeConfig.updateIntervalUnits) {
case 'minutes':
this.updateInterval = interval * (60 * 1000);
break;
case 'hours':
this.updateInterval = interval * (60 * 60 * 1000);
break;
default:
this.updateInterval = interval * 1000;
}
this.timer = setInterval(
this.onTimer.bind(this),
interval * 1000
this.updateInterval
);
}

if (this.nodeConfig.outputonchanged) {
this.addEventClientListener({
event: `ha_events:state_changed:${
this.nodeConfig.entity_id
}`,
event: `ha_events:state_changed:${this.entityId}`,
handler: this.onTimer.bind(this)
});
}
Expand All @@ -55,7 +67,7 @@ module.exports = function(RED) {
}
}

onClose(removed) {
onClose() {
super.onClose();
if (this.timer) {
clearInterval(this.timer);
Expand All @@ -67,81 +79,79 @@ module.exports = function(RED) {
if (!this.isConnected) return;

try {
const pollState = this.utils.merge(
{},
await this.getState(this.nodeConfig.entity_id)
const pollState = await this.nodeConfig.server.homeAssistant.getStates(
this.entityId
);

if (!pollState) {
this.warn(
`could not find state with entity_id "${
this.nodeConfig.entity_id
}"`
`could not find state with entity_id "${this.entityId}"`
);
this.status({
fill: 'red',
shape: 'ring',
text: `no state found for ${this.nodeConfig.entity_id}`
text: `no state found for ${this.entityId}`
});
return;
}

const dateChanged = this.calculateTimeSinceChanged(pollState);
if (dateChanged) {
pollState.timeSinceChanged = ta.ago(dateChanged);
pollState.timeSinceChangedMs =
Date.now() - dateChanged.getTime();

// Convert and save original state if needed
if (
this.nodeConfig.state_type &&
this.nodeConfig.state_type !== 'str'
) {
pollState.original_state = pollState.state;
pollState.state = this.getCastValue(
this.nodeConfig.state_type,
pollState.state
);
}

this.nodeConfig.halt_if_compare =
this.nodeConfig.halt_if_compare || 'is';
this.nodeConfig.halt_if_type =
this.nodeConfig.halt_if_type || 'str';

const shouldHaltIfState =
this.nodeConfig.halt_if &&
(await this.getComparatorResult(
this.nodeConfig.halt_if_compare,
this.nodeConfig.halt_if,
pollState.state,
this.nodeConfig.halt_if_type
));

const msg = {
topic: this.nodeConfig.entity_id,
payload: pollState.state,
data: pollState
};

if (shouldHaltIfState) {
const debugMsg = `poll state: halting processing due to current state of ${
pollState.entity_id
} matches "halt if state" option`;
this.debug(debugMsg);
this.debugToClient(debugMsg);
this.setStatusFailed(pollState.state);
return this.send([null, msg]);
}

this.setStatusSuccess(pollState.state);
this.send([msg, null]);
} else {
if (!dateChanged) {
this.warn(
`could not calculate time since changed for entity_id "${
this.nodeConfig.entity_id
this.entityId
}"`
);
return;
}
pollState.timeSinceChanged = ta.ago(dateChanged);
pollState.timeSinceChangedMs =
Date.now() - dateChanged.getTime();

// Convert and save original state if needed
if (
this.nodeConfig.state_type &&
this.nodeConfig.state_type !== 'str'
) {
pollState.original_state = pollState.state;
pollState.state = this.getCastValue(
this.nodeConfig.state_type,
pollState.state
);
}

this.nodeConfig.halt_if_compare =
this.nodeConfig.halt_if_compare || 'is';
this.nodeConfig.halt_if_type =
this.nodeConfig.halt_if_type || 'str';

const shouldHaltIfState =
this.nodeConfig.halt_if &&
(await this.getComparatorResult(
this.nodeConfig.halt_if_compare,
this.nodeConfig.halt_if,
pollState.state,
this.nodeConfig.halt_if_type
));

const msg = {
topic: this.entityId,
payload: pollState.state,
data: pollState
};

if (shouldHaltIfState) {
const debugMsg = `poll state: halting processing due to current state of ${
pollState.entity_id
} matches "halt if state" option`;
this.debug(debugMsg);
this.debugToClient(debugMsg);
this.setStatusFailed(pollState.state);
return this.send([null, msg]);
}

this.setStatusSuccess(pollState.state);
this.send([msg, null]);
} catch (e) {
throw e;
}
Expand All @@ -151,14 +161,6 @@ module.exports = function(RED) {
const entityLastChanged = entityState.last_changed;
return new Date(entityLastChanged);
}

async getState(entityId) {
let state = await this.nodeConfig.server.homeAssistant.getStates(
this.nodeConfig.entity_id
);

return state;
}
}
RED.nodes.registerType('poll-state', TimeSinceStateNode);
};

0 comments on commit 44f75c0

Please sign in to comment.