Skip to content

Commit

Permalink
feat: Typing for MQTT API (#25098)
Browse files Browse the repository at this point in the history
  • Loading branch information
Nerivec authored Dec 7, 2024
1 parent d891320 commit 1a9c79b
Show file tree
Hide file tree
Showing 18 changed files with 1,088 additions and 291 deletions.
4 changes: 3 additions & 1 deletion lib/controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type {IClientPublishOptions} from 'mqtt';
import type * as SdNotify from 'sd-notify';

import type {Zigbee2MQTTAPI} from './types/api';

import assert from 'assert';

import bind from 'bind-decorator';
Expand Down Expand Up @@ -253,7 +255,7 @@ export class Controller {
}

@bind async publishEntityState(entity: Group | Device, payload: KeyValue, stateChangeReason?: StateChangeReason): Promise<void> {
let message = {...payload};
let message: Zigbee2MQTTAPI['{friendlyName}'] = {...payload};

// Update state cache with new state.
const newState = this.state.set(entity, payload, stateChangeReason);
Expand Down
6 changes: 4 additions & 2 deletions lib/extension/availability.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type {Zigbee2MQTTAPI} from 'lib/types/api';

import assert from 'assert';

import bind from 'bind-decorator';
Expand Down Expand Up @@ -188,9 +190,9 @@ export default class Availability extends Extension {
}

const topic = `${entity.name}/availability`;
const payload = JSON.stringify({state: available ? 'online' : 'offline'});
const payload: Zigbee2MQTTAPI['{friendlyName}/availability'] = {state: available ? 'online' : 'offline'};
this.availabilityCache[entity.ID] = available;
await this.mqtt.publish(topic, payload, {retain: true, qos: 1});
await this.mqtt.publish(topic, JSON.stringify(payload), {retain: true, qos: 1});

if (!skipGroups && entity.isDevice()) {
for (const group of this.zigbee.groupsIterator()) {
Expand Down
32 changes: 15 additions & 17 deletions lib/extension/bind.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type {Zigbee2MQTTAPI, Zigbee2MQTTResponseEndpoints} from 'lib/types/api';

import assert from 'assert';

import bind from 'bind-decorator';
Expand Down Expand Up @@ -207,15 +209,6 @@ interface ParsedMQTTMessage {
resolvedBindTarget?: number | zh.Endpoint | zh.Group;
}

interface DataMessage {
from: ParsedMQTTMessage['sourceKey'];
from_endpoint?: ParsedMQTTMessage['sourceEndpointKey'];
to: ParsedMQTTMessage['targetKey'];
to_endpoint: ParsedMQTTMessage['targetEndpointKey'];
clusters: ParsedMQTTMessage['clusters'];
skip_disable_reporting?: ParsedMQTTMessage['skipDisableReporting'];
}

export default class Bind extends Extension {
private pollDebouncers: {[s: string]: () => void} = {};

Expand All @@ -231,7 +224,7 @@ export default class Bind extends Extension {
if (data.topic.match(TOPIC_REGEX)) {
const type = data.topic.endsWith('unbind') ? 'unbind' : 'bind';
let skipDisableReporting = false;
const message: DataMessage = JSON.parse(data.message);
const message = JSON.parse(data.message) as Zigbee2MQTTAPI['bridge/request/device/bind'];

if (typeof message !== 'object' || message.from == undefined || message.to == undefined) {
return [message, {type, skipDisableReporting}, `Invalid payload`];
Expand Down Expand Up @@ -388,10 +381,10 @@ export default class Bind extends Extension {
return;
}

const responseData: KeyValue = {
from: sourceKey,
from_endpoint: sourceEndpointKey,
to: targetKey,
const responseData: Zigbee2MQTTAPI['bridge/response/device/bind'] | Zigbee2MQTTAPI['bridge/response/device/unbind'] = {
from: sourceKey!, // valid with assert above on `resolvedSource`
from_endpoint: sourceEndpointKey!, // valid with assert above on `resolvedSourceEndpoint`
to: targetKey!, // valid with assert above on `resolvedTarget`
to_endpoint: targetEndpointKey,
clusters: successfulClusters,
failed: failedClusters,
Expand All @@ -412,9 +405,14 @@ export default class Bind extends Extension {
this.eventBus.emitDevicesChanged();
}

private async publishResponse(type: ParsedMQTTMessage['type'], request: KeyValue, data: KeyValue, error?: string): Promise<void> {
const response = stringify(utils.getResponse(request, data, error));
await this.mqtt.publish(`bridge/response/device/${type}`, response);
private async publishResponse<T extends Zigbee2MQTTResponseEndpoints>(
type: ParsedMQTTMessage['type'],
request: KeyValue,
data: Zigbee2MQTTAPI[T],
error?: string,
): Promise<void> {
const response = utils.getResponse(request, data, error);
await this.mqtt.publish(`bridge/response/device/${type}`, stringify(response));

if (error) {
logger.error(error);
Expand Down
Loading

0 comments on commit 1a9c79b

Please sign in to comment.