platform.ts 8.6 KB

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