homebridge-myplace 2.2.3 → 2.3.1

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  ### Homebridge-myplace - An independent plugin for Homebridge bringing Advantage Air MyPlace system, its smaller siblings (E-zone, MyAir, MyAir4, etc) and its cousins (e.g. Fujitsu AnywAir) to Homekit
2
- ##### v2.2.3 (2025-09-11)
2
+ ##### v2.3.1 (2025-10-22)
3
3
 
4
- ###### (1) Increased maxBuffer to 5MB to resolve JOSN truncation issue
5
- ###### (2) Added debugging switch for the plugin
4
+ ###### (1) Allow up to 5 retries of inaccessible device before proceeding to auto-discovery.
5
+ ###### (2) Minor bug fixes.
package/Cmd5Platform.js CHANGED
@@ -4,6 +4,8 @@
4
4
  const { getAccessoryName,
5
5
  getAccessoryDisplayName } = require( "./utils/getAccessoryNameFunctions" );
6
6
  const { parseAddQueueTypes } = require( "./Cmd5PriorityPollingQueue" );
7
+ const { removeTempDir } = require( "./utils/removeTempDir" );
8
+ const { updateConfig } = require( "./utils/updateConfig" );
7
9
 
8
10
  let Logger = require( "./utils/Logger" );
9
11
  let getAccessoryUUID = require( "./utils/getAccessoryUUID" );
@@ -15,7 +17,6 @@ let trueTypeOf = require( "./utils/trueTypeOf" );
15
17
  let HV = require( "./utils/HV" );
16
18
 
17
19
  // Essential variables
18
- const { spawnSync } = require('child_process');
19
20
  let createAccessorysInformationService = require( "./utils/createAccessorysInformationService" );
20
21
 
21
22
  // Pretty Colors
@@ -36,8 +37,6 @@ const Cmd5Accessory = require( "./Cmd5Accessory" ).Cmd5Accessory;
36
37
  // Settings, Globals and Constants
37
38
  let settings = require( "./cmd5Settings" );
38
39
  const constants = require( "./cmd5Constants" );
39
- const path = require('path');
40
- const fs = require('fs');
41
40
 
42
41
  // Platform definition
43
42
  class Cmd5Platform
@@ -105,83 +104,22 @@ class Cmd5Platform
105
104
 
106
105
  // didFinishLaunching is only called after the
107
106
  // registerPlatform completes.
108
- api.on( "didFinishLaunching", ( ) =>
107
+ api.on( "didFinishLaunching", async () =>
109
108
  {
110
109
  this.log.info( chalk.green( "MyPlace Platform didFinishLaunching" ) );
111
110
 
112
- // Remove MyPlace shell script temporary working directories on Homebridge RESTART
113
- this.log.info( chalk.yellow( "Removing temporary working directories" ) );
114
- try {
115
- const directoryPath = process.env.TMPDIR || "/tmp";
116
- const files = fs.readdirSync(directoryPath);
117
- const filteredFiles = files.filter(file => file.match(/^(AA|BB)-\d{3}$/));
118
-
119
- filteredFiles.forEach(file => {
120
- const sdir = `${directoryPath}/${file}`;
121
-
122
- try {
123
- fs.rmSync(sdir, { recursive: true, force: true });
124
- this.log.info(`Temporary working directory ${sdir} removed`);
125
- } catch (err) {
126
- this.log.error(` Unable to remove temporary working directory ${sdir}: [${err}]`);
127
- }
128
- });
129
- } catch (err) {
130
- this.log.error(`Unable to scan and remove temporary working directory: [${err}]`);
131
- }
132
-
133
- // Run ConfigCreator to update/refresh the MyPlace config
134
- this.log.info( chalk.yellow( "Running createMyPlacConfig..." ) );
135
- try {
136
- // Build args for up to 3 devices
137
- let args = [];
138
- for (let i = 0; i < 3; i++) {
139
- const device = this.config.devices[i];
140
- if (device) {
141
- const ipPort = `${device.ipAddress || ''}:${device.port || ''}`;
142
- const name = device.name || '';
143
- const extraTimers = device.extraTimers ?? false;
144
- const debug = device.debug ?? false;
145
- args.push(ipPort, name, extraTimers, debug);
146
- } else {
147
- // If device is missing, push empty args
148
- args.push('', '', '', '');
149
- }
150
- }
151
-
152
- // Add __dirname and "homebridge" as last two arguments
153
- args.push(`${__dirname}/MyPlace.sh`);
154
-
155
- // Run the createMyPlaceconfig.js script
156
- const scriptPath = path.resolve(__dirname, 'utils', 'createMyPlaceConfig.js');
157
- this.log.debug('Running script:', scriptPath, args);
158
-
159
- const result = spawnSync('node', [scriptPath, ...args], { encoding: 'utf8', maxBuffer: 5 * 1024 * 1024 });
111
+ // Update the config
112
+ // The original config has no config for accessories and that needs to be generated by createMyplaceConfig.js
113
+ this.config = await updateConfig( this.config, this.log, __dirname );
160
114
 
161
- const status = result.stderr.trim();
162
- const jsonText = result.stdout.trim();
163
-
164
- if (status.includes('DONE')) {
165
- this.config = JSON.parse(jsonText);
166
- this.log.info(status);
167
- this.log.debug('Updated config:\n' + JSON.stringify(this.config));
168
- } else {
169
- this.log.error(status);
170
- this.log.warn('Proceeding with original config — no accessories will be created.');
171
- }
172
- } catch (err) {
173
- this.log.warn('ERROR: createMyPlaceConfig failed:', err);
174
- this.log.warn('Proceeding with original config — no accessories will be created.');
175
- }
176
-
177
- // Now process these using the updated config
115
+ // Now process this updated config
178
116
  this.parseConfigForCmd5Directives( this.config );
179
117
  this.hV.update( this );
180
118
  this.processNewCharacteristicDefinitions( );
181
119
 
182
- this.log.info( chalk.yellow( "Scanning the config and the cache for devices to be removed or restored from cache" ) );
183
- // scan the platform devices to identify which ones to be restored from cache
184
- this.scanToBeRestoredDevices( this.log );
120
+ // scan the platform accessories (devices) to identify which ones to be restored from cache
121
+ this.log.info( chalk.yellow( "Scanning the config and the cache for accessories to be removed or restored from cache..." ) );
122
+ this.scanToBeRemovedOrRestored( this.log );
185
123
 
186
124
  // Any accessory NOT to be restored should be removed, find them
187
125
  this.toBeRestoredPlatforms.forEach( ( accessory ) =>
@@ -194,6 +132,9 @@ class Cmd5Platform
194
132
  // if it is not already in cache
195
133
  this.discoverDevices( this.log );
196
134
 
135
+ // Remove MyPlace shell script temporary working directories on Homebridge RESTART
136
+ removeTempDir( this.log );
137
+
197
138
  // Let the Polling Begin
198
139
  this.startPolling();
199
140
 
@@ -409,7 +350,7 @@ class Cmd5Platform
409
350
  }
410
351
 
411
352
  // Scan the platform accessories and identify devices to be restored from cache
412
- scanToBeRestoredDevices( )
353
+ scanToBeRemovedOrRestored( )
413
354
  {
414
355
  // Homebridge can only handle a max of 150 accessories per bridge, as such, it is prudent to identify and remove those accessories
415
356
  // which are not to be restored before creating new ones
@@ -475,7 +416,7 @@ class Cmd5Platform
475
416
  let duplicatePlatformAccessory = this.createdCmd5Platforms.find(accessory => accessory.UUID === existingAccessory.UUID);
476
417
  if ( duplicatePlatformAccessory )
477
418
  {
478
- this.log( chalk.red( `Error duplicate platform accessory: ${ duplicatePlatformAccessory.name } uuid:${ duplicatePlatformAccessory.UUID }` ) );
419
+ this.log.error( chalk.red( `Error duplicate platform accessory: ${ duplicatePlatformAccessory.displayName } uuid:${ duplicatePlatformAccessory.UUID }` ) );
479
420
  // Next in for.Each object iteration
480
421
  return;
481
422
  }
@@ -581,6 +522,8 @@ class Cmd5Platform
581
522
 
582
523
  platform.Service = this.Service;
583
524
 
525
+ platform.context.device = device; // ⬅️ Store device config for restoration
526
+
584
527
  this.log.info( chalk.magenta( `Configuring platformAccessory: ` ) + `${ device.displayName }` );
585
528
  let that = this;
586
529
  accessory = new Cmd5Accessory( that.log, device, this.api, [ ], this );
@@ -120,10 +120,10 @@ class Cmd5PriorityPollingQueue
120
120
  if ( this.state_cmd.match( /MyPlace.sh'$/ ) )
121
121
  {
122
122
  // Reject Set requests to change Fanv2 rotationSpeed or to turn off myZone for zones with temperature sensors
123
- if ( this.typeIndex == 20 && this.displayName.match ( / Zone$/ ) &&
124
- ( characteristicString == 'RotationSpeed' ||
125
- ( characteristicString == 'RotationDirection' && value == 1 )
126
- )
123
+ if ( this.typeIndex == 20 && this.displayName.match ( / Zone$/ ) &&
124
+ ( characteristicString == 'RotationSpeed' ||
125
+ ( characteristicString == 'RotationDirection' && value == 1 )
126
+ )
127
127
  )
128
128
  {
129
129
  let storedValue = this.cmd5Storage.getStoredValueForIndex( accTypeEnumIndex );
@@ -132,8 +132,8 @@ class Cmd5PriorityPollingQueue
132
132
  return;
133
133
  }
134
134
  // Reject Set requests to change Thermostat targetHeatingCoolingState for Zone Thermostat
135
- if ( this.typeIndex == 57 && this.displayName.match ( / Thermostat$/ ) &&
136
- characteristicString == 'TargetHeatingCoolingState'
135
+ if ( this.typeIndex == 57 && this.displayName.match ( / Thermostat$/ ) &&
136
+ characteristicString == 'TargetHeatingCoolingState'
137
137
  )
138
138
  {
139
139
  let storedValue = this.cmd5Storage.getStoredValueForIndex( accTypeEnumIndex );
@@ -143,13 +143,13 @@ class Cmd5PriorityPollingQueue
143
143
  }
144
144
  // Turn on the Zone when this Zone is set as myZone
145
145
  else if ( this.typeIndex == 20 && this.displayName.match ( / Zone$/ ) &&
146
- characteristicString == 'RotationDirection' && value == 0
146
+ characteristicString == 'RotationDirection' && value == 0
147
147
  )
148
148
  {
149
149
  this.service.getCharacteristic( 'Active' ).updateValue( 1 );
150
150
  }
151
151
  else if ( this.displayName.match( / FanSpeed$/ ) )
152
- {
152
+ {
153
153
  // Abort if 'on' or 'rotationSpeed' value = 0, this accessory is always on
154
154
  if ( value == 0 )
155
155
  {