Skip to content

Commit

Permalink
feat(time-entity): Add "Expose as" option for Listening mode in time-…
Browse files Browse the repository at this point in the history
…entity node
  • Loading branch information
zachowj committed Sep 9, 2024
1 parent 60d69d2 commit 7ae8c09
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 64 deletions.
1 change: 0 additions & 1 deletion src/nodes/text/TextController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import NoConnectionError from '../../common/errors/NoConnectionError';
import { IntegrationEvent } from '../../common/integration/Integration';
import ValueEntityIntegration from '../../common/integration/ValueEntityIntegration';
import { ValueIntegrationMode } from '../../const';
import { NodeMessage } from '../../types/nodes';
import { EntityConfigNode } from '../entity-config';
import { TextNode, TextNodeProperties } from '.';

Expand Down
20 changes: 0 additions & 20 deletions src/nodes/time-entity/TimeEntityController.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { NodeMessage } from 'node-red';

import InputOutputController, {
InputOutputControllerOptions,
InputProperties,
Expand Down Expand Up @@ -127,24 +125,6 @@ export default class TimeEntityController extends InputOutputController<
}
}

// Triggers when a entity value changes in Home Assistant
public async onValueChange(value: string, previousValue?: string) {
const message: NodeMessage = {};
await this.setCustomOutputs(
this.node.config.outputProperties,
message,
{
config: this.node.config,
value,
previousValue,
},
);

// inject value so colons are not removed
this.status.setSuccess(['__value__', { value }]);
this.node.send(message);
}

/**
* Checks if the given time string is in the format "HH:mm:ss" or "HH:mm".
* @param text The time string to check.
Expand Down
30 changes: 30 additions & 0 deletions src/nodes/time-entity/TimeEntityOutputController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { NodeMessage } from 'node-red';

import ExposeAsMixin from '../../common/controllers/ExposeAsMixin';
import OutputController from '../../common/controllers/OutputController';
import ValueEntityIntegration from '../../common/integration/ValueEntityIntegration';
import { TimeEntityNode } from '.';

const ExposeAsController = ExposeAsMixin(OutputController<TimeEntityNode>);
export default class TimeEntityController extends ExposeAsController {
protected integration?: ValueEntityIntegration;
// Triggers when a entity value changes in Home Assistant
public async onValueChange(value: string, previousValue?: string) {
if (!this.isEnabled) return;

const message: NodeMessage = {};
await this.setCustomOutputs(
this.node.config.outputProperties,
message,
{
config: this.node.config,
value,
previousValue,
},
);

// inject value so colons are not removed
this.status.setSuccess(['__value__', { value }]);
this.node.send(message);
}
}
24 changes: 11 additions & 13 deletions src/nodes/time-entity/editor.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,9 @@
<span data-i18n="ha-time-entity.label.mode"></span>
</label>
<select id="node-input-mode">
<option
value="listen"
data-i18n="ha-time-entity.label.mode_option.listen"
></option>
<option
value="get"
data-i18n="ha-time-entity.label.mode_option.get"
></option>
<option
value="set"
data-i18n="ha-time-entity.label.mode_option.set"
></option>
<option value="listen" data-i18n="ha-time-entity.label.mode_option.listen"></option>
<option value="get" data-i18n="ha-time-entity.label.mode_option.get"></option>
<option value="set" data-i18n="ha-time-entity.label.mode_option.set"></option>
</select>
</div>

Expand All @@ -43,4 +34,11 @@
<input type="hidden" id="node-input-valueType" />
</div>

<div class="form-row"><ol id="custom-outputs"></ol></div>
<div class="form-row">
<ol id="custom-outputs"></ol>
</div>

<div class="form-row" id="exposed-as-row">
<label for="node-input-exposeAsEntityConfig" data-i18n="ha-tag.label.expose_as"></label>
<input type="text" id="node-input-exposeAsEntityConfig" />
</div>
9 changes: 9 additions & 0 deletions src/nodes/time-entity/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ interface TimeEntityEditorNodeProperties extends HassNodeProperties {
mode: ValueIntegrationMode;
value: string;
outputProperties: OutputProperty[];
exposeAsEntityConfig: string;
}

const TimeEntityEditor: EditorNodeDef<TimeEntityEditorNodeProperties> = {
Expand Down Expand Up @@ -47,6 +48,13 @@ const TimeEntityEditor: EditorNodeDef<TimeEntityEditorNodeProperties> = {
filter: (config) => config.entityType === 'time',
required: true,
},
exposeAsEntityConfig: {
value: '',
type: NodeType.EntityConfig,
// @ts-ignore - DefinitelyTyped is missing this property
filter: (config) => config.entityType === EntityType.Switch,
required: false,
},
mode: { value: ValueIntegrationMode.Listen },
value: { value: 'payload' },
valueType: { value: TypedInputTypes.Message },
Expand All @@ -73,6 +81,7 @@ const TimeEntityEditor: EditorNodeDef<TimeEntityEditorNodeProperties> = {
exposeNode.init(this);

saveEntityType(EntityType.Time);
saveEntityType(EntityType.Switch, 'exposeAsEntityConfig');
$('#dialog-form').prepend(ha.betaWarning(988));

const $valueRow = $('#node-input-value').parent();
Expand Down
93 changes: 63 additions & 30 deletions src/nodes/time-entity/index.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
import Joi from 'joi';

import { createControllerDependencies } from '../../common/controllers/helpers';
import {
createControllerDependencies,
createExposeAsControllerDependences,
} from '../../common/controllers/helpers';
import Events from '../../common/events/Events';
import { IntegrationEvent } from '../../common/integration/Integration';
import InputService, { NodeInputs } from '../../common/services/InputService';
import Status from '../../common/status/Status';
import { TypedInputTypes, ValueIntegrationMode } from '../../const';
import { RED } from '../../globals';
import { migrate } from '../../helpers/migrate';
import { getConfigNodes } from '../../helpers/node';
import { getConfigNodes, getExposeAsConfigNode } from '../../helpers/node';
import { getHomeAssistant } from '../../homeAssistant/index';
import {
BaseNode,
EntityBaseNodeProperties,
OutputProperty,
} from '../../types/nodes';
import TextOutputController from '../text/TextOutputController';
import TimeEntityController from './TimeEntityController';

export interface TimeEntityNodeProperties extends EntityBaseNodeProperties {
mode: ValueIntegrationMode;
value: string;
valueType: string;
outputProperties: OutputProperty[];
exposeAsEntityConfig: string;
}

export interface TimeEntityNode extends BaseNode {
Expand Down Expand Up @@ -64,36 +69,64 @@ export default function timeEntityNode(
const { entityConfigNode, serverConfigNode } = getConfigNodes(this);
const homeAssistant = getHomeAssistant(serverConfigNode);

const status = new Status({
config: serverConfigNode.config,
node: this,
});
switch (this.config.mode) {
case ValueIntegrationMode.Get:
case ValueIntegrationMode.Set:
{
const status = new Status({
config: serverConfigNode.config,
node: this,
});

const controllerDeps = createControllerDependencies(
this,
homeAssistant,
);
const inputService = new InputService<TimeEntityNodeProperties>(
{
inputs,
nodeConfig: this.config,
schema: inputSchema,
},
);

const controllerDeps = createControllerDependencies(this, homeAssistant);
const inputService = new InputService<TimeEntityNodeProperties>({
inputs,
nodeConfig: this.config,
schema: inputSchema,
});
entityConfigNode.integration.setStatus(status);
// eslint-disable-next-line no-new
new TimeEntityController({
inputService,
integration: entityConfigNode.integration,
node: this,
status,
...controllerDeps,
});
}
break;
case ValueIntegrationMode.Listen: {
const exposeAsConfigNode = getExposeAsConfigNode(
this.config.exposeAsEntityConfig,
);
const controllerDeps = createExposeAsControllerDependences({
exposeAsConfigNode,
homeAssistant,
node: this,
serverConfigNode,
});

entityConfigNode.integration.setStatus(status);
const controller = new TimeEntityController({
inputService,
integration: entityConfigNode.integration,
node: this,
status,
...controllerDeps,
});
const controller = new TextOutputController({
node: this,
...controllerDeps,
});
controller.setExposeAsConfigNode(exposeAsConfigNode);

if (this.config.mode === ValueIntegrationMode.Listen) {
const entityConfigEvents = new Events({
node: this,
emitter: entityConfigNode,
});
entityConfigEvents.setStatus(status);
entityConfigEvents.addListener(
IntegrationEvent.ValueChange,
controller.onValueChange.bind(controller),
);
const entityConfigEvents = new Events({
node: this,
emitter: entityConfigNode,
});
entityConfigEvents.setStatus(controllerDeps.status);
entityConfigEvents.addListener(
IntegrationEvent.ValueChange,
controller.onValueChange.bind(controller),
);
}
}
}

0 comments on commit 7ae8c09

Please sign in to comment.