Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support for Z-Wave JS v13 #3799

Merged
merged 13 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 9 additions & 14 deletions api/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@ import jsonStore from './lib/jsonStore'
import * as loggers from './lib/logger'
import MqttClient from './lib/MqttClient'
import SocketManager from './lib/SocketManager'
import ZWaveClient, {
CallAPIResult,
configManager,
loadManager,
SensorTypeScale,
} from './lib/ZwaveClient'
import ZWaveClient, { CallAPIResult, SensorTypeScale } from './lib/ZwaveClient'
import multer, { diskStorage } from 'multer'
import extract from 'extract-zip'
import { serverVersion } from '@zwave-js/server'
Expand Down Expand Up @@ -49,6 +44,7 @@ import backupManager from './lib/BackupManager'
import { readFile, realpath } from 'fs/promises'
import { generate } from 'selfsigned'
import ZnifferManager, { ZnifferConfig } from './lib/ZnifferManager'
import { getAllNamedScaleGroups, getAllSensors } from '@zwave-js/core'

const createCertificate = promisify(generate)

Expand Down Expand Up @@ -258,7 +254,6 @@ export async function startServer(port: number | string, host?: string) {
setupSocket(server)
setupInterceptor()
await loadSnippets()
await loadManager()
startZniffer(settings.zniffer)
await startGateway(settings)
}
Expand Down Expand Up @@ -1061,15 +1056,15 @@ app.get(
apisLimiter,
isAuthenticated,
async function (req, res) {
const sensorTypes = configManager.sensorTypes
const sensorScalesGroups = configManager.namedScales
const allSensors = getAllSensors()
const namedScaleGroups = getAllNamedScaleGroups()

const scales: SensorTypeScale[] = []

for (const [key, group] of sensorScalesGroups) {
for (const [, scale] of group) {
for (const group of namedScaleGroups) {
for (const scale of Object.values(group.scales)) {
scales.push({
key: key,
key: group.name,
sensor: group.name,
unit: scale.unit,
label: scale.label,
Expand All @@ -1078,8 +1073,8 @@ app.get(
}
}

for (const [, sensor] of sensorTypes) {
for (const [, scale] of sensor.scales) {
for (const sensor of allSensors) {
for (const scale of Object.values(sensor.scales)) {
scales.push({
key: sensor.key,
sensor: sensor.label,
Expand Down
18 changes: 6 additions & 12 deletions api/lib/Constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ConfigManager } from '@zwave-js/config'
import { getMeter, getMeterScale } from '@zwave-js/core'

interface IGenericMap {
[key: number]: string
Expand Down Expand Up @@ -113,19 +113,13 @@ export function productionType(index: number): Record<string, any> {
},
}
}
export function meterType(
ccSpecific: IMeterCCSpecific,
configManager: ConfigManager,
): any {
const meter = configManager.lookupMeter(ccSpecific.meterType)
const scale = configManager.lookupMeterScale(
ccSpecific.meterType,
ccSpecific.scale,
)
export function meterType(ccSpecific: IMeterCCSpecific): any {
const meter = getMeter(ccSpecific.meterType)
const scale = getMeterScale(ccSpecific.meterType, ccSpecific.scale)

const cfg = {
sensor: meter ? meter.name : 'unknown',
objectId: scale ? scale.label : `unknown${ccSpecific.scale}`,
sensor: meter?.name || 'unknown',
objectId: scale?.label || `unknown${ccSpecific.scale}`,
props: {},
}

Expand Down
1 change: 0 additions & 1 deletion api/lib/Gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1566,7 +1566,6 @@ export default class Gateway {
if (valueId.ccSpecific) {
sensor = Constants.meterType(
valueId.ccSpecific as IMeterCCSpecific,
this._zwave.driver.configManager,
)

sensor.objectId += '_' + valueId.property
Expand Down
23 changes: 11 additions & 12 deletions api/lib/ZwaveClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ import {
InclusionUserCallbacks,
InclusionState,
ProvisioningEntryStatus,
AssociationCheckResult,
} from 'zwave-js'
import { getEnumMemberName, parseQRCodeString } from 'zwave-js/Utils'
import { logsDir, nvmBackupsDir, storeDir } from '../config/app'
Expand All @@ -127,11 +128,6 @@ export const configManager = new ConfigManager({
deviceConfigPriorityDir,
})

export async function loadManager() {
await configManager.loadNamedScales()
await configManager.loadSensorTypes()
}
robertsLando marked this conversation as resolved.
Show resolved Hide resolved

const logger = LogManager.module('Z-Wave')
// eslint-disable-next-line @typescript-eslint/no-var-requires
const loglevels = require('triple-beam').configs.npm.levels
Expand Down Expand Up @@ -1778,13 +1774,13 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
if (zwaveNode) {
try {
for (const a of associations) {
if (
this._driver.controller.isAssociationAllowed(
const checkResult =
this._driver.controller.checkAssociation(
source,
groupId,
a,
)
) {
if (checkResult === AssociationCheckResult.OK) {
this.logNode(
zwaveNode,
'info',
Expand All @@ -1802,7 +1798,8 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
this.logNode(
zwaveNode,
'warn',
`Unable to add Node ${a.nodeId} to Group ${groupId} of ${sourceMsg}, association not allowed`,
// FIXME: We should explain the reason why it failed in human-readable form, see doc comments of AssociationCheckResult
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still TODO

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you mean on frontend side?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both logs and frontend IMO

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check what i did and let me know if it's ok for you

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although, if we do #3801, we don't have to show the error reason in the logs I think, because there shouldn't be one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there shouldn't doesn't mean there will not, also consider that api can be also called from driver function and MQTT so I would leave it there

`Unable to add Node ${a.nodeId} to Group ${groupId} of ${sourceMsg}: ${getEnumMemberName(AssociationCheckResult, checkResult)}`,
)
}
}
Expand Down Expand Up @@ -4602,9 +4599,11 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
}
}

private _onInclusionStarted(secure: boolean) {
private _onInclusionStarted(strategy: InclusionStrategy) {
const secure = strategy !== InclusionStrategy.Insecure
const message = `${secure ? 'Secure' : 'Non-secure'} inclusion started`
this._updateControllerStatus(message)
// FIXME: Should the frontend also accept the strategy instead of the boolean?
this.emit('event', EventSource.CONTROLLER, 'inclusion started', secure)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See FIXME comment

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Frontend uses startInclusion and passes the mode:

this.sendAction('startInclusion', [
mode,
{ provisioning },
])

this.sendAction('startInclusion', [
mode,
{
forceSecurity: s.values.forceSecurity,
dsk,
...this.nodeProps,
},
])

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant the event that is emitted below the comment. Right now it gets passed secure, I wonder if it should now include the strategy instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that event actually is only emittet to MQTT when Emit events flag is enabled in MQTT settings, nothing used by UI btw. I can fix that and use the inclusion strategy instead

}

Expand Down Expand Up @@ -5571,7 +5570,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
this.logNode(
endpoint.nodeId,
'error',
`Notification received but node doesn't exists`,
`Notification received but node doesn't exist`,
)

return
Expand Down Expand Up @@ -5985,7 +5984,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
node.keepAwake = zwaveNode.keepAwake
node.maxDataRate = zwaveNode.maxDataRate
node.deviceClass = {
basic: zwaveNode.deviceClass?.basic.key,
basic: zwaveNode.deviceClass?.basic,
generic: zwaveNode.deviceClass?.generic.key,
specific: zwaveNode.deviceClass?.specific.key,
}
Expand Down
Loading
Loading