@@ -4,6 +4,7 @@ import { API } from 'homebridge';
44import * as WebSocket from 'ws' ;
55import { Logging } from 'homebridge' ;
66import { HsdAccessory } from './hsdAccessory' ;
7+ import { randomUUID } from 'crypto' ;
78
89export enum CONNECTION_STATE {
910 INIT = 0 ,
@@ -16,11 +17,14 @@ export enum CONNECTION_STATE {
1617
1718export class HomeServerConnector {
1819
20+ private static _instance : HomeServerConnector ;
21+
1922 private _ws : WebSocket . WebSocket | null = null ;
2023 private _connState = CONNECTION_STATE . INIT ;
2124 private _transactionIdCnt = 0 ;
2225 private _listeners : Map < string , ( reading : string ) => void > = new Map ( ) ;
2326 private _msgQueu = { } ;
27+ private _uuid = '' ;
2428
2529 private requestPromiseResolver : Map < string , ( value : string | PromiseLike < string > ) => void > = new Map ( ) ;
2630
@@ -33,11 +37,33 @@ export class HomeServerConnector {
3337 private _user = '' ;
3438 private _pw = '' ;
3539
40+ private _errorCodes = {
41+ 0 : 'Everything is fine.' ,
42+ 400 : 'Invalid request (Bad Request).' ,
43+ 403 : 'Access denied (Forbidden). Check if the read/write flag is set for the user groups on the Endpoint-tab.' ,
44+ 404 : 'The requested HS-Object does not exist in the called context.' ,
45+ 500 : 'An error occurred in the server when generating the response.' ,
46+ 901 : 'The specified key is invalid.' ,
47+ 902 : 'reserved' ,
48+ 903 : 'The object parameters are invalid.' ,
49+ 904 : 'The object is not subscribed.' ,
50+ } ;
51+
3652 /**
3753 *
3854 */
39- constructor ( private api : API , private logger : Logging , private accessory : Map < string , HsdAccessory > ) {
40- //
55+ private constructor ( private api : API , private logger : Logging , private accessory : Map < string , HsdAccessory > ) {
56+ this . _uuid = randomUUID ( ) ;
57+ }
58+
59+ // This static method controls the access to the singleton instance.
60+ // On the first run, it creates the instance and stores it in a static field.
61+ // On subsequent runs, it returns the stored instance.
62+ public static getInstance ( api : API , logger : Logging , accessory : Map < string , HsdAccessory > ) : HomeServerConnector {
63+ if ( ! HomeServerConnector . _instance ) {
64+ HomeServerConnector . _instance = new HomeServerConnector ( api , logger , accessory ) ;
65+ }
66+ return HomeServerConnector . _instance ;
4167 }
4268
4369 /**
@@ -56,6 +82,11 @@ export class HomeServerConnector {
5682 * @param pw
5783 */
5884 connect ( hsIp : string , hsPort : number , user : string , pw : string ) {
85+ if ( ( this . _connState === CONNECTION_STATE . OPEN ) || ( this . _connState === CONNECTION_STATE . CONNECTING ) ) {
86+ return ; // already connected
87+ }
88+ this . logger . info ( 'hs.ts | HomeServerConnector | connect > Current connection state is %d' , this . _connState ) ;
89+
5990 this . _hsIp = hsIp ;
6091 this . _hsPort = hsPort ;
6192 this . _user = user ;
@@ -67,7 +98,7 @@ export class HomeServerConnector {
6798
6899 this . _ws . on ( 'open' , ( ) => {
69100 this . _connState = CONNECTION_STATE . OPEN ;
70- this . logger . info ( 'Connected to HS' ) ;
101+ this . logger . info ( 'Connected to HS by %s' , this . _uuid ) ;
71102 } ) ;
72103
73104 this . _ws . on ( 'message' , ( message : string ) => {
@@ -102,10 +133,17 @@ export class HomeServerConnector {
102133
103134 if ( code !== 0 ) {
104135 if ( 'request' in jsonMsg ) {
105- this . logger . error ( 'hs.ts | HomeserverConnector | receivedMessage > Error and aborting due to code %d for %s requesting %s' ,
106- code ,
107- jsonMsg . request . key ,
108- jsonMsg . request . method ) ;
136+ if ( code in this . _errorCodes ) {
137+ this . logger . error ( 'hs.ts | HomeserverConnector | receivedMessage > Error and aborting due to "%s" for %s requesting %s' ,
138+ this . _errorCodes [ code ] ,
139+ jsonMsg . request . key ,
140+ jsonMsg . request . method ) ;
141+ } else {
142+ this . logger . error ( 'hs.ts | HomeserverConnector | receivedMessage > Error and aborting due to code %d for %s requesting %s' ,
143+ code ,
144+ jsonMsg . request . key ,
145+ jsonMsg . request . method ) ;
146+ }
109147 } else {
110148 this . logger . error ( 'hs.ts | HomeserverConnector | receivedMessage > Error and aborting due to %s' , message ) ;
111149 }
@@ -120,21 +158,31 @@ export class HomeServerConnector {
120158 this . logger . debug ( 'hs.ts | HomeserverConnector | Received select/subscribe message' ) ;
121159 for ( const item of data . items ) {
122160 if ( item . code !== 0 ) {
123- this . logger . error ( 'hs.ts | HomeserverConnector | receivedMessage > Error and aborting due to code %s for %s requesting %s' ,
124- item . code ,
125- item . key ,
126- type ) ;
127- return false ;
128- }
129- endpoint = item . key ;
130- value = String ( item . data . value ) ;
161+ if ( 'request' in jsonMsg ) {
162+ if ( code in this . _errorCodes ) {
163+ this . logger . error ( 'hs.ts | HomeserverConnector | receivedMessage > Error and aborting due to "%s" for %s requesting %s' ,
164+ this . _errorCodes [ item . code ] ,
165+ item . key ,
166+ type ) ;
167+ } else {
168+ this . logger . error ( 'hs.ts | HomeserverConnector | receivedMessage > Error and aborting due to code %d for %s requesting %s' ,
169+ item . code ,
170+ item . key ,
171+ type ) ;
172+ }
173+ return false ;
174+ }
131175
132- /// return value via callback
133- const callback = this . _listeners . get ( endpoint ) ;
134- if ( callback ) {
135- callback ( value ) ;
136- } else {
137- this . logger . warn ( 'hs.ts | HomeserverConnector | No callback for %s registered' , endpoint ) ;
176+ endpoint = item . key ;
177+ value = String ( item . data . value ) ;
178+
179+ /// return value via callback
180+ const callback = this . _listeners . get ( endpoint ) ;
181+ if ( callback ) {
182+ callback ( value ) ;
183+ } else {
184+ this . logger . warn ( 'hs.ts | HomeserverConnector | No callback for %s registered' , endpoint ) ;
185+ }
138186 }
139187 }
140188
0 commit comments