platform.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. import { API, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service, Characteristic } from 'homebridge'
  2. import { PLATFORM_NAME, PLUGIN_NAME } from './settings'
  3. import { accessory } from './accessory'
  4. import { device } from './device'
  5. import { klikAanKlikUitAccessory } from './klikAanKlikUitAccessory'
  6. import { powerSocketAccessory } from './powerSocketAccessory'
  7. import { powerSwitchAccessory } from './powerSwitchAccessory'
  8. import { environmentSensorAccessory } from './environmentSensorAccessory'
  9. import { doorWindowSensorAccessory } from './doorWindowSensorAccessory'
  10. import { motionSensorAccessory } from './motionSensorAccessory'
  11. import { cameraAccessory } from './cameraAccessory'
  12. //import { activityAccessory } from './activityAccessory'
  13. import { thermostatAccessory } from './thermostatAccessory'
  14. import { smokeDetectorAccessory } from './smokeDetectorAccessory'
  15. import { securitySystemAccessory } from './securitySystemAccessory'
  16. import { httpServer } from './httpServer'
  17. export class domoticaPlatform implements DynamicPlatformPlugin {
  18. public readonly Service: typeof Service = this.api.hap.Service
  19. public readonly Characteristic: typeof Characteristic = this.api.hap.Characteristic
  20. public readonly accessories: accessory[] = []
  21. public readonly cachedAccessories: PlatformAccessory[] = []
  22. public readonly presentAccessories: PlatformAccessory[] = []
  23. private readonly discoveries: String[] = []
  24. private readonly completedDiscoveries: String[] = []
  25. private httpServer: httpServer = new httpServer(this, this.config)
  26. constructor(
  27. public readonly log: Logger,
  28. public readonly config: PlatformConfig,
  29. public readonly api: API
  30. ) {
  31. this.api.on('didFinishLaunching', () => {
  32. this.discoverDevices()
  33. this.httpServer.start()
  34. })
  35. }
  36. configureAccessory(accessory: PlatformAccessory) {
  37. this.cachedAccessories.push(accessory)
  38. }
  39. discoverDevices() {
  40. this.discoveryStarted('klikAanKlikUitAccessory')
  41. klikAanKlikUitAccessory.discoverDevices(this)
  42. .then((devices) => {
  43. this.processDiscoveredDevices(devices)
  44. this.discoveryCompleted('klikAanKlikUitAccessory')
  45. })
  46. .catch((error) => {
  47. this.log.debug('klikAanKlikUitAccessory.discoverDevices Error ->' + error)
  48. })
  49. this.discoveryStarted('powerSocketAccessory')
  50. powerSocketAccessory.discoverDevices(this)
  51. .then((devices) => {
  52. this.processDiscoveredDevices(devices)
  53. this.discoveryCompleted('powerSocketAccessory')
  54. })
  55. .catch((error) => {
  56. this.log.debug('powerSocketAccessory.discoverDevices Error ->' + error)
  57. })
  58. this.discoveryStarted('powerSwitchAccessory')
  59. powerSwitchAccessory.discoverDevices(this)
  60. .then((devices) => {
  61. this.processDiscoveredDevices(devices)
  62. this.discoveryCompleted('powerSwitchAccessory')
  63. })
  64. .catch((error) => {
  65. this.log.debug('powerSwitchAccessory.discoverDevices Error ->' + error)
  66. })
  67. this.discoveryStarted('environmentSensorAccessory')
  68. environmentSensorAccessory.discoverDevices(this)
  69. .then((devices) => {
  70. this.processDiscoveredDevices(devices)
  71. this.discoveryCompleted('environmentSensorAccessory')
  72. })
  73. .catch((error) => {
  74. this.log.debug('environmentSensorAccessory.discoverDevices Error ->' + error)
  75. })
  76. this.discoveryStarted('doorWindowSensorAccessory')
  77. doorWindowSensorAccessory.discoverDevices(this)
  78. .then((devices) => {
  79. this.processDiscoveredDevices(devices)
  80. this.discoveryCompleted('doorWindowSensorAccessory')
  81. })
  82. .catch((error) => {
  83. this.log.debug('doorWindowSensorAccessory.discoverDevices Error ->' + error)
  84. })
  85. this.discoveryStarted('motionSensorAccessory')
  86. motionSensorAccessory.discoverDevices(this)
  87. .then((devices) => {
  88. this.processDiscoveredDevices(devices)
  89. this.discoveryCompleted('motionSensorAccessory')
  90. })
  91. .catch((error) => {
  92. this.log.debug('motionSensorAccessory.discoverDevices Error ->' + error)
  93. })
  94. this.discoveryStarted('cameraAccessory')
  95. cameraAccessory.discoverDevices(this)
  96. .then((devices) => {
  97. this.processDiscoveredDevices(devices)
  98. this.discoveryCompleted('cameraAccessory')
  99. })
  100. .catch((error) => {
  101. this.log.debug('cameraAccessory.discoverDevices Error ->' + error)
  102. })
  103. // this.discoveryStarted('activityAccessory')
  104. // activityAccessory.discoverDevices(this)
  105. // .then((devices) => {
  106. // this.processDiscoveredDevices(devices)
  107. // this.discoveryCompleted('activityAccessory')
  108. // })
  109. // .catch((error) => {
  110. // this.log.debug('activityAccessory.discoverDevices Error ->' + error)
  111. // })
  112. this.discoveryStarted('thermostatAccessory')
  113. thermostatAccessory.discoverDevices(this)
  114. .then((devices) => {
  115. this.processDiscoveredDevices(devices)
  116. this.discoveryCompleted('thermostatAccessory')
  117. })
  118. .catch((error) => {
  119. this.log.debug('thermostatAccessory.discoverDevices Error ->' + error)
  120. })
  121. this.discoveryStarted('smokeDetectorAccessory')
  122. smokeDetectorAccessory.discoverDevices(this)
  123. .then((devices) => {
  124. this.processDiscoveredDevices(devices)
  125. this.discoveryCompleted('smokeDetectorAccessory')
  126. })
  127. .catch((error) => {
  128. this.log.debug('smokeDetectorAccessory.discoverDevices Error ->' + error)
  129. })
  130. this.discoveryStarted('securitySystemAccessory')
  131. securitySystemAccessory.discoverDevices(this)
  132. .then((devices) => {
  133. this.processDiscoveredDevices(devices)
  134. this.discoveryCompleted('securitySystemAccessory')
  135. })
  136. .catch((error) => {
  137. this.log.debug('securitySystemAccessory.discoverDevices Error ->' + error)
  138. })
  139. }
  140. processDiscoveredDevices(domoticaDevices: device[]) {
  141. for (const device of domoticaDevices) {
  142. const uuid = this.api.hap.uuid.generate(device.uniqueId)
  143. const existingAccessory = this.cachedAccessories.find(accessory => accessory.UUID === uuid)
  144. if (existingAccessory) {
  145. this.log.info('| ' + existingAccessory.context.device.type + ': ' + existingAccessory.displayName)
  146. this.presentAccessories.push(existingAccessory)
  147. if (existingAccessory.displayName != device.deviceName) {
  148. this.log.info('! ' + existingAccessory.displayName + ' => ' + device.deviceName)
  149. existingAccessory.context.device = device
  150. this.api.updatePlatformAccessories([existingAccessory])
  151. }
  152. if (existingAccessory.context.device.type == 'KlikAanKlikUit') {
  153. this.accessories.push(new klikAanKlikUitAccessory(this, existingAccessory))
  154. } else if (existingAccessory.context.device.type == 'PowerSocket') {
  155. this.accessories.push(new powerSocketAccessory(this, existingAccessory))
  156. } else if (existingAccessory.context.device.type == 'PowerSwitch') {
  157. this.accessories.push(new powerSwitchAccessory(this, existingAccessory))
  158. } else if (existingAccessory.context.device.type == 'EnvironmentSensor') {
  159. this.accessories.push(new environmentSensorAccessory(this, existingAccessory))
  160. } else if (existingAccessory.context.device.type == 'DoorWindowSensor') {
  161. this.accessories.push(new doorWindowSensorAccessory(this, existingAccessory))
  162. } else if (existingAccessory.context.device.type == 'MotionSensor') {
  163. this.accessories.push(new motionSensorAccessory(this, existingAccessory))
  164. } else if (existingAccessory.context.device.type == 'Camera') {
  165. this.accessories.push(new cameraAccessory(this, existingAccessory))
  166. // } else if (existingAccessory.context.device.type == 'Activity') {
  167. // this.accessories.push(new activityAccessory(this, existingAccessory))
  168. } else if (existingAccessory.context.device.type == 'Thermostat') {
  169. this.accessories.push(new thermostatAccessory(this, existingAccessory))
  170. } else if (existingAccessory.context.device.type == 'SmokeDetector') {
  171. this.accessories.push(new smokeDetectorAccessory(this, existingAccessory))
  172. } else if (existingAccessory.context.device.type == 'SecuritySystem') {
  173. this.accessories.push(new securitySystemAccessory(this, existingAccessory))
  174. }
  175. } else {
  176. this.log.info('+ ' + device.type + ': ' + device.deviceName)
  177. const accessory = new this.api.platformAccessory(device.deviceName, uuid)
  178. accessory.context.device = device
  179. if (accessory.context.device.type == 'KlikAanKlikUit') {
  180. this.accessories.push(new klikAanKlikUitAccessory(this, accessory))
  181. } else if (accessory.context.device.type == 'PowerSocket') {
  182. this.accessories.push(new powerSocketAccessory(this, accessory))
  183. } else if (accessory.context.device.type == 'PowerSwitch') {
  184. this.accessories.push(new powerSwitchAccessory(this, accessory))
  185. } else if (accessory.context.device.type == 'EnvironmentSensor') {
  186. this.accessories.push(new environmentSensorAccessory(this, accessory))
  187. } else if (accessory.context.device.type == 'DoorWindowSensor') {
  188. this.accessories.push(new doorWindowSensorAccessory(this, accessory))
  189. } else if (accessory.context.device.type == 'MotionSensor') {
  190. this.accessories.push(new motionSensorAccessory(this, accessory))
  191. } else if (accessory.context.device.type == 'Camera') {
  192. this.accessories.push(new cameraAccessory(this, accessory))
  193. // } else if (accessory.context.device.type == 'Activity') {
  194. // this.accessories.push(new activityAccessory(this, accessory))
  195. } else if (accessory.context.device.type == 'Thermostat') {
  196. this.accessories.push(new thermostatAccessory(this, accessory))
  197. } else if (accessory.context.device.type == 'SmokeDetector') {
  198. this.accessories.push(new smokeDetectorAccessory(this, accessory))
  199. } else if (accessory.context.device.type == 'SecuritySystem') {
  200. this.accessories.push(new securitySystemAccessory(this, accessory))
  201. }
  202. this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory])
  203. }
  204. }
  205. }
  206. discoveryStarted(deviceType) {
  207. this.discoveries.push(deviceType)
  208. }
  209. discoveryCompleted(deviceType) {
  210. this.completedDiscoveries.push(deviceType)
  211. if (this.completedDiscoveries.length == this.discoveries.length) {
  212. this.cleanupRemovedDevices()
  213. }
  214. //setInterval(this.updateAccessories.bind(this), 60 * 1000); // Poll every minute
  215. }
  216. updateAccessories() {
  217. for (const accessory of this.accessories) {
  218. accessory.update()
  219. }
  220. }
  221. cleanupRemovedDevices() {
  222. for (const existingAccessory of this.cachedAccessories) {
  223. const presentAccessory = this.presentAccessories.find(accessory => accessory.UUID === existingAccessory.UUID)
  224. if (!presentAccessory) {
  225. this.log.info('- ' + existingAccessory.context.device.type + ': ' + existingAccessory.displayName)
  226. this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory])
  227. }
  228. }
  229. }
  230. }