homebridge-nest-accfactory 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +31 -25
- package/config.schema.json +46 -22
- package/dist/HomeKitDevice.js +523 -281
- package/dist/HomeKitHistory.js +357 -341
- package/dist/config.js +69 -87
- package/dist/consts.js +160 -0
- package/dist/devices.js +40 -48
- package/dist/ffmpeg.js +297 -0
- package/dist/index.js +3 -3
- package/dist/nexustalk.js +182 -149
- package/dist/plugins/camera.js +1164 -933
- package/dist/plugins/doorbell.js +26 -32
- package/dist/plugins/floodlight.js +11 -24
- package/dist/plugins/heatlink.js +411 -5
- package/dist/plugins/lock.js +309 -0
- package/dist/plugins/protect.js +240 -71
- package/dist/plugins/tempsensor.js +159 -35
- package/dist/plugins/thermostat.js +891 -455
- package/dist/plugins/weather.js +128 -33
- package/dist/protobuf/nest/services/apigateway.proto +1 -1
- package/dist/protobuf/nestlabs/gateway/v2.proto +1 -1
- package/dist/protobuf/root.proto +1 -0
- package/dist/rtpmuxer.js +186 -0
- package/dist/streamer.js +490 -248
- package/dist/system.js +1741 -2868
- package/dist/utils.js +327 -0
- package/dist/webrtc.js +358 -229
- package/package.json +19 -16
|
@@ -6,43 +6,38 @@
|
|
|
6
6
|
|
|
7
7
|
// Define our modules
|
|
8
8
|
import HomeKitDevice from '../HomeKitDevice.js';
|
|
9
|
+
import { processCommonData, adjustTemperature, scaleValue } from '../utils.js';
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
// Define constants
|
|
12
|
+
import { LOW_BATTERY_LEVEL, DATA_SOURCE, PROTOBUF_RESOURCES, DEVICE_TYPE } from '../consts.js';
|
|
11
13
|
|
|
12
14
|
export default class NestTemperatureSensor extends HomeKitDevice {
|
|
13
15
|
static TYPE = 'TemperatureSensor';
|
|
14
|
-
static VERSION = '2025.
|
|
16
|
+
static VERSION = '2025.08.04'; // Code version
|
|
15
17
|
|
|
16
18
|
batteryService = undefined;
|
|
17
19
|
temperatureService = undefined;
|
|
18
20
|
|
|
19
|
-
constructor(accessory, api, log, eventEmitter, deviceData) {
|
|
20
|
-
super(accessory, api, log, eventEmitter, deviceData);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
21
|
// Class functions
|
|
24
|
-
|
|
25
|
-
// Setup temperature service if not already present on the accessory
|
|
26
|
-
this.temperatureService = this.addHKService(this.hap.Service.TemperatureSensor, '', 1);
|
|
22
|
+
onAdd() {
|
|
23
|
+
// Setup temperature service if not already present on the accessory and link it to the Eve app if configured to do so
|
|
24
|
+
this.temperatureService = this.addHKService(this.hap.Service.TemperatureSensor, '', 1, {});
|
|
27
25
|
this.temperatureService.setPrimaryService();
|
|
28
26
|
|
|
29
27
|
// Setup battery service if not already present on the accessory
|
|
30
28
|
this.batteryService = this.addHKService(this.hap.Service.Battery, '', 1);
|
|
31
29
|
this.batteryService.setHiddenService(true);
|
|
30
|
+
this.temperatureService.addLinkedService(this.batteryService);
|
|
31
|
+
}
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
) {
|
|
39
|
-
this.historyService.linkToEveHome(this.temperatureService, {
|
|
40
|
-
description: this.deviceData.description,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
33
|
+
onRemove() {
|
|
34
|
+
this.accessory.removeService(this.temperatureService);
|
|
35
|
+
this.accessory.removeService(this.batteryService);
|
|
36
|
+
this.temperatureService = undefined;
|
|
37
|
+
this.batteryService = undefined;
|
|
43
38
|
}
|
|
44
39
|
|
|
45
|
-
|
|
40
|
+
onUpdate(deviceData) {
|
|
46
41
|
if (typeof deviceData !== 'object' || this.temperatureService === undefined || this.batteryService === undefined) {
|
|
47
42
|
return;
|
|
48
43
|
}
|
|
@@ -70,26 +65,155 @@ export default class NestTemperatureSensor extends HomeKitDevice {
|
|
|
70
65
|
this.batteryService.updateCharacteristic(this.hap.Characteristic.BatteryLevel, deviceData.battery_level);
|
|
71
66
|
this.batteryService.updateCharacteristic(
|
|
72
67
|
this.hap.Characteristic.StatusLowBattery,
|
|
73
|
-
deviceData.battery_level >
|
|
68
|
+
deviceData.battery_level > LOW_BATTERY_LEVEL
|
|
74
69
|
? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL
|
|
75
70
|
: this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW,
|
|
76
71
|
);
|
|
77
72
|
this.batteryService.updateCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE);
|
|
78
73
|
|
|
79
74
|
// If we have the history service running and temperature has changed to previous in past 5mins
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
{
|
|
88
|
-
time: Math.floor(Date.now() / 1000),
|
|
89
|
-
temperature: deviceData.current_temperature,
|
|
90
|
-
},
|
|
91
|
-
300,
|
|
92
|
-
);
|
|
93
|
-
}
|
|
75
|
+
this.history(
|
|
76
|
+
this.temperatureService,
|
|
77
|
+
{
|
|
78
|
+
temperature: deviceData.current_temperature,
|
|
79
|
+
},
|
|
80
|
+
{ timegap: 300, force: true },
|
|
81
|
+
);
|
|
94
82
|
}
|
|
95
83
|
}
|
|
84
|
+
|
|
85
|
+
// Function to process our RAW Nest or Google for this device type
|
|
86
|
+
export function processRawData(log, rawData, config, deviceType = undefined) {
|
|
87
|
+
if (
|
|
88
|
+
rawData === null ||
|
|
89
|
+
typeof rawData !== 'object' ||
|
|
90
|
+
rawData?.constructor !== Object ||
|
|
91
|
+
typeof config !== 'object' ||
|
|
92
|
+
config?.constructor !== Object
|
|
93
|
+
) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Process data for any temperature sensors we have in the raw data
|
|
98
|
+
// We do this using any thermostat data
|
|
99
|
+
let devices = {};
|
|
100
|
+
Object.entries(rawData)
|
|
101
|
+
.filter(
|
|
102
|
+
([key, value]) =>
|
|
103
|
+
key.startsWith('device.') === true ||
|
|
104
|
+
(key.startsWith('DEVICE_') === true && PROTOBUF_RESOURCES.THERMOSTAT.includes(value.value?.device_info?.typeName) === true),
|
|
105
|
+
)
|
|
106
|
+
.forEach(([object_key, value]) => {
|
|
107
|
+
try {
|
|
108
|
+
if (
|
|
109
|
+
value?.source === DATA_SOURCE.GOOGLE &&
|
|
110
|
+
value.value?.configuration_done?.deviceReady === true &&
|
|
111
|
+
Array.isArray(value.value?.remote_comfort_sensing_settings?.associatedRcsSensors) === true
|
|
112
|
+
) {
|
|
113
|
+
value.value.remote_comfort_sensing_settings.associatedRcsSensors.forEach((sensor) => {
|
|
114
|
+
if (typeof rawData?.[sensor?.deviceId?.resourceId]?.value === 'object') {
|
|
115
|
+
let sensorData = rawData[sensor.deviceId.resourceId].value;
|
|
116
|
+
let tempDevice = processCommonData(
|
|
117
|
+
sensor.deviceId.resourceId,
|
|
118
|
+
{
|
|
119
|
+
type: DEVICE_TYPE.TEMPSENSOR,
|
|
120
|
+
model: 'Temperature Sensor',
|
|
121
|
+
softwareVersion: NestTemperatureSensor.VERSION, // We'll use our class version here now
|
|
122
|
+
serialNumber: sensorData.device_identity.serialNumber,
|
|
123
|
+
description: String(sensorData?.label?.label ?? ''),
|
|
124
|
+
location: String(
|
|
125
|
+
[
|
|
126
|
+
...Object.values(
|
|
127
|
+
rawData?.[sensorData?.device_info?.pairerId?.resourceId]?.value?.located_annotations?.predefinedWheres || {},
|
|
128
|
+
),
|
|
129
|
+
...Object.values(
|
|
130
|
+
rawData?.[sensorData?.device_info?.pairerId?.resourceId]?.value?.located_annotations?.customWheres || {},
|
|
131
|
+
),
|
|
132
|
+
].find((where) => where?.whereId?.resourceId === sensorData?.device_located_settings?.whereAnnotationRid?.resourceId)
|
|
133
|
+
?.label?.literal ?? '',
|
|
134
|
+
),
|
|
135
|
+
// Guessing battery minimum voltage is 2v??
|
|
136
|
+
battery_level: scaleValue(Number(sensorData.battery.assessedVoltage.value), 2.0, 3.0, 0, 100),
|
|
137
|
+
current_temperature: adjustTemperature(sensorData.current_temperature.temperatureValue.temperature.value, 'C', 'C', true),
|
|
138
|
+
online:
|
|
139
|
+
isNaN(sensorData?.last_updated_beacon?.lastBeaconTime?.seconds) === false &&
|
|
140
|
+
Math.floor(Date.now() / 1000) - Number(sensorData.last_updated_beacon.lastBeaconTime.seconds) < 3600 * 4,
|
|
141
|
+
associated_thermostat: object_key,
|
|
142
|
+
active_sensor:
|
|
143
|
+
value.value?.remote_comfort_sensing_settings?.activeRcsSelection?.activeRcsSensor?.resourceId ===
|
|
144
|
+
sensor.deviceId.resourceId,
|
|
145
|
+
},
|
|
146
|
+
config,
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
if (
|
|
150
|
+
Object.entries(tempDevice).length !== 0 &&
|
|
151
|
+
typeof devices[tempDevice.serialNumber] === 'undefined' &&
|
|
152
|
+
(deviceType === undefined || (typeof deviceType === 'string' && deviceType !== '' && tempDevice.type === deviceType))
|
|
153
|
+
) {
|
|
154
|
+
let deviceOptions = config?.devices?.find(
|
|
155
|
+
(device) => device?.serialNumber?.toUpperCase?.() === tempDevice?.serialNumber?.toUpperCase?.(),
|
|
156
|
+
);
|
|
157
|
+
// Insert any extra options we've read in from configuration file for this device
|
|
158
|
+
tempDevice.eveHistory = config.options.eveHistory === true || deviceOptions?.eveHistory === true;
|
|
159
|
+
devices[tempDevice.serialNumber] = tempDevice; // Store processed device
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (
|
|
166
|
+
value?.source === DATA_SOURCE.NEST &&
|
|
167
|
+
Array.isArray(rawData?.['rcs_settings.' + value.value?.serial_number]?.value?.associated_rcs_sensors) === true
|
|
168
|
+
) {
|
|
169
|
+
rawData['rcs_settings.' + value.value.serial_number].value.associated_rcs_sensors.forEach((sensor) => {
|
|
170
|
+
if (
|
|
171
|
+
typeof rawData[sensor]?.value === 'object' &&
|
|
172
|
+
typeof rawData?.['where.' + rawData?.[sensor]?.value?.structure_id] === 'object'
|
|
173
|
+
) {
|
|
174
|
+
let sensorData = rawData[sensor].value;
|
|
175
|
+
let tempDevice = processCommonData(
|
|
176
|
+
sensor,
|
|
177
|
+
{
|
|
178
|
+
type: DEVICE_TYPE.TEMPSENSOR,
|
|
179
|
+
model: 'Temperature Sensor',
|
|
180
|
+
softwareVersion: NestTemperatureSensor.VERSION, // We'll use our class version here now
|
|
181
|
+
serialNumber: sensorData.serial_number,
|
|
182
|
+
battery_level: scaleValue(Number(sensorData.battery_level), 0, 100, 0, 100),
|
|
183
|
+
current_temperature: adjustTemperature(sensorData.current_temperature, 'C', 'C', true),
|
|
184
|
+
online: Math.floor(Date.now() / 1000) - sensorData.last_updated_at < 3600 * 4,
|
|
185
|
+
associated_thermostat: object_key,
|
|
186
|
+
description: String(sensorData.description?.trim() ?? ''),
|
|
187
|
+
location: String(
|
|
188
|
+
rawData?.['where.' + sensorData.structure_id]?.value?.wheres?.find((where) => where?.where_id === sensorData.where_id)
|
|
189
|
+
?.name ?? '',
|
|
190
|
+
),
|
|
191
|
+
active_sensor:
|
|
192
|
+
rawData?.['rcs_settings.' + value.value.serial_number]?.value?.active_rcs_sensors?.includes?.(object_key) === true,
|
|
193
|
+
},
|
|
194
|
+
config,
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
if (
|
|
198
|
+
Object.entries(tempDevice).length !== 0 &&
|
|
199
|
+
typeof devices[tempDevice.serialNumber] === 'undefined' &&
|
|
200
|
+
(deviceType === undefined || (typeof deviceType === 'string' && deviceType !== '' && tempDevice.type === deviceType))
|
|
201
|
+
) {
|
|
202
|
+
let deviceOptions = config?.devices?.find(
|
|
203
|
+
(device) => device?.serialNumber?.toUpperCase?.() === tempDevice?.serialNumber?.toUpperCase?.(),
|
|
204
|
+
);
|
|
205
|
+
// Insert any extra options we've read in from configuration file for this device
|
|
206
|
+
tempDevice.eveHistory = config.options.eveHistory === true || deviceOptions?.eveHistory === true;
|
|
207
|
+
devices[tempDevice.serialNumber] = tempDevice; // Store processed device
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
// eslint-disable-next-line no-unused-vars
|
|
213
|
+
} catch (error) {
|
|
214
|
+
log?.debug?.('Error processing temperature sensor data for "%s"', object_key);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
return devices;
|
|
219
|
+
}
|