-
-
Notifications
You must be signed in to change notification settings - Fork 99
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: Add custom integration nodes - sensor node: create sensor and binary sensor in HA - webhook: create a webhook in HA that will be handled by NR - event nodes: add ability to expose each event node to HA as a switch * fix(integration): Set HA Config defaults for old nodes * fix: Stop sending removal payload when node is not actually registered * refactor: Improve error message for missing integration * docs: Note about custom integration needed for certain nodes * refactor(entity): Add more state types for binary_sensor * fix: Enabled event nodes that are exposed HA when integration is removed from HA * feat(webhook): Add request headers to msg object * fix(sensor): Make sure lastPayload is being saved * feat(webhook): Add custom location output for payload and headers * fix: Check that the node is registered with HA before attempting to remove it * fix: Check that exposedNodes exists * refactor: Handle options that depend on custom integration more graceful when integration is not installed * refactor: Check that a server is selected before setting exposedNodes * docs: Add documentation for the new nodes * feat(entity): Add customizable output location * feat(entity): Add debug information output for discovery and update * refactor(entity): Test for connection before attempting to update * refactor: Set default values for config values
- Loading branch information
Showing
22 changed files
with
1,487 additions
and
161 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
const merge = require('lodash.merge'); | ||
const EventsNode = require('./events-node'); | ||
|
||
const DEFAULT_NODE_OPTIONS = { | ||
debug: false, | ||
config: { | ||
name: {}, | ||
server: { | ||
isNode: true | ||
}, | ||
haConfig: {}, | ||
exposeToHomeAssistant: nodeDef => | ||
nodeDef.exposeToHomeAssistant === undefined | ||
? false | ||
: nodeDef.exposeToHomeAssistant | ||
} | ||
}; | ||
|
||
class EventsHaNode extends EventsNode { | ||
constructor(nodeDefinition, RED, nodeOptions = {}) { | ||
nodeOptions = merge({}, DEFAULT_NODE_OPTIONS, nodeOptions); | ||
super(nodeDefinition, RED, nodeOptions); | ||
this.isEnabled = true; | ||
|
||
// Check if there's a server selected | ||
if (this.nodeConfig.server) { | ||
// Determine if node needs to be removed from Home Assistant because it's no longer exposed | ||
this.removeFromHA = !!( | ||
this.nodeConfig.exposeToHomeAssistant === false && | ||
this.nodeConfig.server.exposedNodes[this.id] === true | ||
); | ||
// Save expose state so we can check if it needs to removed when it's not exposed anymore | ||
this.nodeConfig.server.exposedNodes[ | ||
this.id | ||
] = this.nodeConfig.exposeToHomeAssistant; | ||
} | ||
this.loadPersistedData(); | ||
|
||
if (this.isConnected) { | ||
this.registerEntity(); | ||
this.removeFromHomeAssistant(); | ||
} | ||
} | ||
|
||
async onClose(removed) { | ||
super.onClose(removed); | ||
|
||
if (removed) { | ||
if (this.isConnected && this.nodeConfig.exposeToHomeAssistant) { | ||
this.removeFromHomeAssistant(true); | ||
} | ||
await this.removeNodeData(); | ||
} | ||
|
||
this.removeSubscription(); | ||
} | ||
|
||
async onHaConfigUpdate() { | ||
this.registerEntity(); | ||
this.removeFromHomeAssistant(); | ||
} | ||
|
||
onHaIntegration(type) { | ||
if (type === 'loaded') { | ||
this.registerEntity(); | ||
} else if (type === 'unloaded') { | ||
this.isEnabled = true; | ||
this.registered = false; | ||
if (this.subscription) { | ||
this.subscription(); | ||
this.subscription = null; | ||
} | ||
this.updateConnectionStatus(); | ||
} | ||
} | ||
|
||
async loadPersistedData() { | ||
try { | ||
const data = await this.getNodeData(); | ||
if ( | ||
data && | ||
Object.prototype.hasOwnProperty.call(data, 'isEnabled') | ||
) { | ||
this.isEnabled = data.isEnabled; | ||
this.updateConnectionStatus(); | ||
} | ||
} catch (e) { | ||
this.error(e.message); | ||
} | ||
} | ||
|
||
async registerEntity() { | ||
if (this.subscription || super.registerEntity() === false) { | ||
return; | ||
} | ||
|
||
const haConfig = {}; | ||
this.nodeConfig.haConfig | ||
.filter(c => { | ||
return c.value.length; | ||
}) | ||
.forEach(e => { | ||
haConfig[e.property] = e.value; | ||
}); | ||
|
||
const payload = { | ||
type: 'nodered/discovery', | ||
server_id: this.nodeConfig.server.id, | ||
node_id: this.id, | ||
component: 'switch', | ||
state: this.isEnabled, | ||
config: haConfig | ||
}; | ||
|
||
this.subscription = await this.websocketClient.client.subscribeMessage( | ||
this.onEvent.bind(this), | ||
payload | ||
); | ||
|
||
this.setStatusSuccess('Registered'); | ||
this.registered = true; | ||
} | ||
|
||
async onEvent(evt) { | ||
this.isEnabled = evt.state; | ||
this.saveNodeData('isEnabled', this.isEnabled); | ||
this.updateHomeAssistant(); | ||
this.updateConnectionStatus(); | ||
} | ||
|
||
async updateHomeAssistant() { | ||
const message = { | ||
type: 'nodered/entity', | ||
server_id: this.nodeConfig.server.id, | ||
node_id: this.id, | ||
state: this.isEnabled | ||
}; | ||
|
||
this.websocketClient.send(message); | ||
} | ||
|
||
// Remove from Home Assistant when `Expose to Home Assistant` is unchecked | ||
removeFromHomeAssistant(nodeRemoved = false) { | ||
if ( | ||
this.websocketClient.integrationVersion === 0 || | ||
(!this.removeFromHA && !nodeRemoved) | ||
) { | ||
return; | ||
} | ||
|
||
const payload = { | ||
type: 'nodered/discovery', | ||
server_id: this.nodeConfig.server.id, | ||
node_id: this.id, | ||
component: 'switch', | ||
remove: true | ||
}; | ||
|
||
this.websocketClient.send(payload); | ||
this.removeFromHA = false; | ||
this.removeSubscription(); | ||
|
||
// Enabled node when removing it from Home Assistant as there is no | ||
// way to do so once it's removed except for the trigger-state node | ||
this.isEnabled = true; | ||
this.saveNodeData('isEnabled', this.isEnabled); | ||
} | ||
|
||
removeSubscription() { | ||
if (this.subscription) { | ||
this.subscription(); | ||
this.subscription = null; | ||
} | ||
} | ||
} | ||
|
||
module.exports = EventsHaNode; |
Oops, something went wrong.