Skip to content

Commit

Permalink
feat(select): Add "Expose as" option for Listening mode in select node
Browse files Browse the repository at this point in the history
  • Loading branch information
zachowj committed Sep 9, 2024
1 parent e7441e1 commit 8dfffb3
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 53 deletions.
1 change: 1 addition & 0 deletions src/nodes/number/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ interface NumberEditorNodeProperties extends HassNodeProperties {
entityConfig: any;
mode: ValueIntegrationMode;
outputProperties: OutputProperty[];
exposeAsEntityConfig: string;
}

const NumberEditor: EditorNodeDef<NumberEditorNodeProperties> = {
Expand Down
17 changes: 0 additions & 17 deletions src/nodes/select/SelectController.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 { SelectNode, SelectNodeProperties } from '.';

Expand Down Expand Up @@ -132,20 +131,4 @@ export default class SelectController extends InputOutputController<

return options.includes(option);
}

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

this.status.setSuccess(value);
this.node.send(message);
}
}
28 changes: 28 additions & 0 deletions src/nodes/select/SelectOutputController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import ExposeAsMixin from '../../common/controllers/ExposeAsMixin';
import OutputController from '../../common/controllers/OutputController';
import ValueEntityIntegration from '../../common/integration/ValueEntityIntegration';
import { NodeMessage } from '../../types/nodes';
import { SelectNode } from '.';

const ExposeAsController = ExposeAsMixin(OutputController<SelectNode>);
export default class SelectOutputController extends ExposeAsController {
protected integration?: ValueEntityIntegration;

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,
},
);

this.status.setSuccess(value);
this.node.send(message);
}
}
14 changes: 9 additions & 5 deletions src/nodes/select/editor.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@
<span data-i18n="ha-select.label.mode"></span>
</label>
<select id="node-input-mode">
<option
value="listen"
data-i18n="ha-text.label.mode_option.listen"
></option>
<option value="listen" data-i18n="ha-text.label.mode_option.listen"></option>
<option value="get" data-i18n="ha-text.label.mode_option.get"></option>
<option value="set" data-i18n="ha-text.label.mode_option.set"></option>
</select>
Expand All @@ -37,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>
11 changes: 10 additions & 1 deletion src/nodes/select/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ interface SelectEditorNodeProperties extends HassNodeProperties {
entityConfig: any;
mode: ValueIntegrationMode;
outputProperties: OutputProperty[];
exposeAsEntityConfig: string;
}

const SelectEditor: EditorNodeDef<SelectEditorNodeProperties> = {
Expand All @@ -43,9 +44,16 @@ const SelectEditor: EditorNodeDef<SelectEditorNodeProperties> = {
value: '',
type: NodeType.EntityConfig,
// @ts-ignore - DefinitelyTyped is missing this property
filter: (config) => config.entityType === 'select',
filter: (config) => config.entityType === EntityType.Select,
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 @@ -72,6 +80,7 @@ const SelectEditor: EditorNodeDef<SelectEditorNodeProperties> = {
exposeNode.init(this);

saveEntityType(EntityType.Select);
saveEntityType(EntityType.Switch, 'exposeAsEntityConfig');

$('#dialog-form').prepend(ha.betaWarning(968));

Expand Down
93 changes: 63 additions & 30 deletions src/nodes/select/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 SelectController from './SelectController';
import SelectOutputController from './SelectOutputController';

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

export interface SelectNode extends BaseNode {
Expand Down Expand Up @@ -63,36 +68,64 @@ export default function selectNode(

const { entityConfigNode, serverConfigNode } = getConfigNodes(this);
const homeAssistant = getHomeAssistant(serverConfigNode);
const status = new Status({
config: serverConfigNode.config,
node: this,
});

const controllerDeps = createControllerDependencies(this, homeAssistant);
const inputService = new InputService<SelectNodeProperties>({
inputs,
nodeConfig: this.config,
schema: inputSchema,
});
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<SelectNodeProperties>({
inputs,
nodeConfig: this.config,
schema: inputSchema,
});

entityConfigNode.integration.setStatus(status);
const controller = new SelectController({
inputService,
integration: entityConfigNode.integration,
node: this,
status,
...controllerDeps,
});
entityConfigNode.integration.setStatus(status);
// eslint-disable-next-line no-new
new SelectController({
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,
});

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 controller = new SelectOutputController({
node: this,
...controllerDeps,
});
controller.setExposeAsConfigNode(exposeAsConfigNode);
const entityConfigEvents = new Events({
node: this,
emitter: entityConfigNode,
});
entityConfigEvents.setStatus(controllerDeps.status);
entityConfigEvents.addListener(
IntegrationEvent.ValueChange,
controller.onValueChange.bind(controller),
);
}
break;
}
}

0 comments on commit 8dfffb3

Please sign in to comment.