Advertisement
Guest User

Untitled

a guest
Jan 8th, 2016
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 38.86 KB | None | 0 0
  1. module.exports = (env) ->
  2.  
  3. Promise = env.require 'bluebird'
  4. assert = env.require 'cassert'
  5. _ = env.require 'lodash'
  6. events = env.require 'events'
  7. M = env.matcher
  8.  
  9. V_TEMP = 0
  10. V_HUM = 1
  11. V_STATUS = 2
  12. V_LIGHT = 2
  13. V_PERCENTAGE = 3
  14. V_DIMMER = 3
  15. V_PRESSURE = 4
  16. V_FORECAST = 5
  17. V_RAIN = 6
  18. V_RAINRATE = 7
  19. V_WIND = 8
  20. V_GUST = 9
  21. V_DIRECTION = 10
  22. V_UV = 11
  23. V_WEIGHT = 12
  24. V_DISTANCE = 13
  25. V_IMPEDANCE = 14
  26. V_ARMED = 15
  27. V_TRIPPED = 16
  28. V_WATT = 17
  29. V_KWH = 18
  30. V_SCENE_ON = 19
  31. V_SCENE_OFF = 20
  32. V_HEATER = 21
  33. V_HEATER_SW = 22
  34. V_LIGHT_LEVEL = 23
  35. V_VAR1 = 24
  36. V_VAR2 = 25
  37. V_VAR3 = 26
  38. V_VAR4 = 27
  39. V_VAR5 = 28
  40. V_UP = 29
  41. V_DOWN = 30
  42. V_STOP = 31
  43. V_IR_SEND = 32
  44. V_IR_RECEIVE = 33
  45. V_FLOW = 34
  46. V_VOLUME = 35
  47. V_LOCK_STATUS = 36
  48. V_LEVEL = 37
  49. V_VOLTAGE = 38
  50. V_CURRENT = 39
  51. V_RGB = 40
  52. V_RGBW = 41
  53. V_ID = 42
  54. V_UNIT_PREFIX = 43
  55. V_HVAC_SETPOINT_COOL = 44
  56. V_HVAC_SETPOINT_HEAT = 45
  57. V_HVAC_FLOW_MODE = 46
  58.  
  59. ZERO_VALUE = "0"
  60.  
  61. FIRMWARE_BLOCK_SIZE = 16
  62. BROADCAST_ADDRESS = 255
  63. NODE_SENSOR_ID = 255
  64.  
  65. C_PRESENTATION = 0
  66. C_SET = 1
  67. C_REQ = 2
  68. C_INTERNAL = 3
  69. C_STREAM = 4
  70.  
  71.  
  72. I_BATTERY_LEVEL = 0
  73. I_TIME = 1
  74. I_VERSION = 2
  75. I_ID_REQUEST = 3
  76. I_ID_RESPONSE = 4
  77. I_INCLUSION_MODE = 5
  78. I_CONFIG = 6
  79. I_PING = 7
  80. I_PING_ACK = 8
  81. I_LOG_MESSAGE = 9
  82. I_CHILDREN = 10
  83. I_SKETCH_NAME = 11
  84. I_SKETCH_VERSION = 12
  85. I_REBOOT = 13
  86.  
  87. S_DOOR = 0
  88. S_MOTION = 1
  89. S_SMOKE = 2
  90. S_LIGHT = 3
  91. S_DIMMER = 4
  92. S_COVER = 5
  93. S_TEMP = 6
  94. S_HUM = 7
  95. S_BARO = 8
  96. S_WIND = 9
  97. S_RAIN = 10
  98. S_UV = 11
  99. S_WEIGHT = 12
  100. S_POWER = 13
  101. S_HEATER = 14
  102. S_DISTANCE = 15
  103. S_LIGHT_LEVEL = 16
  104. S_ARDUINO_NODE = 17
  105. S_ARDUINO_REPEATER_NODE = 18
  106. S_LOCK = 19
  107. S_IR = 20
  108. S_WATER = 21
  109. S_AIR_QUALITY = 22
  110.  
  111. ST_FIRMWARE_CONFIG_REQUEST = 0
  112. ST_FIRMWARE_CONFIG_RESPONSE = 1
  113. ST_FIRMWARE_REQUEST = 2
  114. ST_FIRMWARE_RESPONSE = 3
  115. ST_SOUND = 4
  116. ST_IMAGE = 5
  117.  
  118. P_STRING = 0
  119. P_BYTE = 1
  120. P_INT16 = 2
  121. P_UINT16 = 3
  122. P_LONG32 = 4
  123. P_ULONG32 = 5
  124. P_CUSTOM = 6
  125.  
  126.  
  127. class Board extends events.EventEmitter
  128.  
  129. constructor: (framework,config) ->
  130. @config = config
  131. @framework = framework
  132. assert @config.driver in ["serialport", "gpio"]
  133. # setup a new driver
  134. switch @config.driver
  135. when "serialport"
  136. SerialPortDriver = require './serialport'
  137. @driver = new SerialPortDriver(@config.driverOptions)
  138.  
  139. @driver.on('error', (error) => @emit('error', error) )
  140. @driver.on('reconnect', (error) => @emit('reconnect', error) )
  141. @driver.on('close', =>
  142.  
  143. @emit('close')
  144. )
  145. @driver.on("data", (data) =>
  146. @emit "data", data
  147. )
  148. @driver.on("line", (line) =>
  149. @emit "line", line
  150. @_rfReceived(line)
  151. )
  152.  
  153.  
  154. connect: (timeout = 20000, retries = 3) ->
  155.  
  156. return @pendingConnect = @driver.connect(timeout, retries)
  157.  
  158. disconnect: ->
  159.  
  160. return @driver.disconnect()
  161.  
  162. _rfReceived: (data) ->
  163. # decoding message
  164. datas = {};
  165. datas = data.toString().split(";")
  166. sender = parseInt datas[0]
  167.  
  168. sensor = parseInt datas[1]
  169. command = parseInt datas[2]
  170. ack = parseInt datas[3]
  171. type = parseInt datas[4]
  172. rawpayload = ""
  173.  
  174. if (datas[5])
  175. rawpayload = datas[5].trim()
  176.  
  177. switch command
  178. when C_PRESENTATION
  179. env.logger.debug "<- Presented Node ", datas
  180. when C_SET
  181. @_rfsendtoboard(sender,sensor,type,rawpayload)
  182. when C_REQ
  183. env.logger.debug "<- request from ", sender, rawpayload
  184. @_rfrequest(sender,sensor,type)
  185. when C_INTERNAL
  186. switch type
  187. when I_BATTERY_LEVEL
  188. env.logger.debug "<- I_BATTERY_LEVEL ", sender, rawpayload
  189. @_rfsendbatterystat(sender,rawpayload)
  190. when I_TIME
  191. env.logger.debug "<- I_TIME ", data
  192. @_rfsendTime(sender, sensor)
  193. when I_VERSION
  194. env.logger.debug "<- I_VERSION ", payload
  195. when I_ID_REQUEST
  196. env.logger.debug "<- I_ID_REQUEST ", data
  197. @_rfsendNextAvailableSensorId()
  198. when I_ID_RESPONSE
  199. env.logger.debug "<- I_ID_RESPONSE ", data
  200. when I_INCLUSION_MODE
  201. env.logger.debug "<- I_INCLUSION_MODE ", data
  202. when I_CONFIG
  203. env.logger.debug "<- I_CONFIG ", data
  204. @_rfsendConfig(sender)
  205. when I_PING
  206. env.logger.debug "<- I_PING ", data
  207. when I_PING_ACK
  208. env.logger.debug "<- I_PING_ACK ", data
  209. when I_LOG_MESSAGE
  210. env.logger.debug "<- I_LOG_MESSAGE ", data
  211. when I_CHILDREN
  212. env.logger.debug "<- I_CHILDREN ", data
  213. when I_SKETCH_NAME
  214. #saveSketchName(sender, payload, db);
  215. env.logger.debug "<- I_SKETCH_NAME ", data
  216. when I_SKETCH_VERSION
  217. #saveSketchVersion(sender, payload, db);
  218. env.logger.debug "<- I_SKETCH_VERSION ", data
  219.  
  220.  
  221. _rfsendTime: (destination,sensor) ->
  222. payload = Math.floor((new Date().getTime())/1000)
  223. datas = {}
  224. datas =
  225. {
  226. "destination": destination,
  227. "sensor": sensor,
  228. "type" : I_TIME,
  229. "ack" : 0,
  230. "command" : C_INTERNAL,
  231. "value" : payload
  232. }
  233. @_rfWrite( datas)
  234.  
  235.  
  236. _rfsendNextAvailableSensorId: ->
  237. datas = {}
  238. nextnodeid = @config.startingNodeId
  239. if nextnodeid > 255
  240. env.logger.debug "-> Error assigning Next ID, already reached maximum ID"
  241. return
  242. if nextnodeid is null
  243. nextnodeid = 1
  244. else
  245. nextnodeid +=1
  246. datas =
  247. {
  248. "destination": BROADCAST_ADDRESS,
  249. "sensor": NODE_SENSOR_ID,
  250. "type" : I_ID_RESPONSE,
  251. "ack" : 0,
  252. "command" : C_INTERNAL,
  253. "value" : nextnodeid
  254. }
  255. @config.startingNodeId = nextnodeid
  256. @_rfWrite(datas)
  257. @framework.saveConfig()
  258.  
  259. _rfrequest: (sender,sensor,type) ->
  260. result = {}
  261. result = {
  262. "sender": sender,
  263. "sensor": sensor,
  264. "type": type
  265. }
  266. @emit "rfRequest", result
  267.  
  268. _rfsendtoboard: (sender,sensor,type,rawpayload) ->
  269. result = {}
  270. result = {
  271. "sender": sender,
  272. "sensor": sensor,
  273. "type" : type,
  274. "value" : rawpayload
  275. }
  276. @emit "rfValue", result
  277.  
  278. _rfsendbatterystat: (sender,rawpayload) ->
  279. result = {}
  280. result = {
  281. "sender": sender,
  282. "value" : rawpayload
  283. }
  284. @emit "rfbattery", result
  285.  
  286. _rfsendConfig: (destination) ->
  287. datas = {}
  288. datas = {
  289. "destination": destination,
  290. "sensor": NODE_SENSOR_ID,
  291. "type" : I_CONFIG,
  292. "ack" : 0,
  293. "command" : C_INTERNAL,
  294. "value" : @config.metric
  295. }
  296. @_rfWrite(datas)
  297.  
  298. _rfWrite: (datas) ->
  299. datas.command ?= C_SET
  300. data = @_rfencode(datas.destination,datas.sensor,datas.command,datas.ack,datas.type,datas.value)
  301. env.logger.debug "-> Sending ", data
  302. @driver.write(data)
  303.  
  304. _rfencode: (destination, sensor, command, acknowledge, type, payload) ->
  305. msg = destination.toString(10) + ";" + sensor.toString(10) + ";" + command.toString(10) + ";" + acknowledge.toString(10) + ";" + type.toString(10) + ";";
  306. msg += payload
  307. msg += '\n'
  308. return msg.toString()
  309.  
  310. Promise.promisifyAll(Board.prototype)
  311. ## MySensors class.
  312. class MySensors extends env.plugins.Plugin
  313.  
  314. init: (app, @framework, @config) =>
  315. @board = new Board(@framework, @config)
  316.  
  317. @board.connect().then( =>
  318. env.logger.info("Connected to MySensors Gateway.")
  319. )
  320.  
  321. deviceConfigDef = require("./device-config-schema")
  322.  
  323. @framework.ruleManager.addActionProvider(new MySensorsActionProvider @framework,@board, config)
  324.  
  325. deviceClasses = [
  326. MySensorsDHT
  327. MySensorsDST
  328. MySensorsBMP
  329. MySensorsPIR
  330. MySensorsSwitch
  331. MySensorsDimmer
  332. MySensorsPulseMeter
  333. MySensorsButton
  334. MySensorsLight
  335. MySensorsLux
  336. MySensorsDistance
  337. MySensorsGas
  338. MySensorsMulti
  339. ]
  340.  
  341. for Cl in deviceClasses
  342. do (Cl) =>
  343. @framework.deviceManager.registerDeviceClass(Cl.name, {
  344. configDef: deviceConfigDef[Cl.name]
  345. createCallback: (config,lastState) =>
  346. device = new Cl(config,lastState, @board)
  347. return device
  348. })
  349. # registerDevice for MySensorsBattery device
  350. @framework.deviceManager.registerDeviceClass(MySensorsBattery.name, {
  351. configDef: deviceConfigDef[MySensorsBattery.name]
  352. createCallback: (config,lastState) =>
  353. device = new MySensorsBattery(config,lastState, @board,@framework)
  354. return device
  355. })
  356.  
  357. class MySensorsDHT extends env.devices.TemperatureSensor
  358.  
  359. constructor: (@config,lastState, @board) ->
  360. @id = config.id
  361. @name = config.name
  362. @_temperatue = lastState?.temperature?.value
  363. @_humidity = lastState?.humidity?.value
  364. @_batterystat = lastState?.batterystat?.value
  365. env.logger.info "MySensorsDHT " , @id , @name
  366.  
  367. @attributes = {}
  368.  
  369. @attributes.temperature = {
  370. description: "the messured temperature"
  371. type: "number"
  372. unit: '°C'
  373. acronym: 'T'
  374. }
  375.  
  376. @attributes.humidity = {
  377. description: "the messured humidity"
  378. type: "number"
  379. unit: '%'
  380. acronym: 'RH'
  381. }
  382.  
  383. @attributes.battery = {
  384. description: "Display the battery level of Sensor"
  385. type: "number"
  386. unit: '%'
  387. acronym: 'BATT'
  388. hidden: !@config.batterySensor
  389. }
  390.  
  391. @board.on("rfbattery", (result) =>
  392. if result.sender is @config.nodeid
  393. unless result.value is null or undefined
  394. # When the battery is to low, battery percentages higher then 100 could be send
  395. if result.value > 100
  396. result.value = 0
  397.  
  398. @_batterystat = parseInt(result.value)
  399. @emit "battery" , @_batterystat
  400. )
  401.  
  402. @board.on("rfValue", (result) =>
  403. if result.sender is @config.nodeid
  404. for sensorid in @config.sensorid
  405. if result.sensor is sensorid
  406. env.logger.info "<- MySensorDHT " , result
  407. if result.type is V_TEMP
  408. #env.logger.info "temp" , result.value
  409. @_temperatue = parseFloat(result.value)
  410. @emit "temperature", @_temperatue
  411. if result.type is V_HUM
  412. #env.logger.info "humidity" , result.value
  413. @_humidity = Math.round(parseFloat(result.value))
  414. @emit "humidity", @_humidity
  415. )
  416. super()
  417.  
  418. getTemperature: -> Promise.resolve @_temperatue
  419. getHumidity: -> Promise.resolve @_humidity
  420. getBattery: -> Promise.resolve @_batterystat
  421.  
  422. class MySensorsDST extends env.devices.TemperatureSensor
  423.  
  424. constructor: (@config,lastState, @board) ->
  425. @id = config.id
  426. @name = config.name
  427. @_temperatue = lastState?.temperature?.value
  428. @_batterystat = lastState?.batterystat?.value
  429. env.logger.debug "MySensorsDST " , @id , @name
  430.  
  431. @attributes = {}
  432.  
  433. @attributes.temperature = {
  434. description: "the messured temperature"
  435. type: "number"
  436. unit: '°C'
  437. acronym: 'T'
  438. }
  439.  
  440. @attributes.battery = {
  441. description: "Display the battery level of Sensor"
  442. type: "number"
  443. unit: '%'
  444. acronym: 'BATT'
  445. hidden: !@config.batterySensor
  446. }
  447.  
  448. @board.on("rfbattery", (result) =>
  449. if result.sender is @config.nodeid
  450. unless result.value is null or undefined
  451. # When the battery is to low, battery percentages higher then 100 could be send
  452. if result.value > 100
  453. result.value = 0
  454.  
  455. @_batterystat = parseInt(result.value)
  456. @emit "battery" , @_batterystat
  457. )
  458.  
  459. @board.on("rfValue", (result) =>
  460. if result.sender is @config.nodeid and result.type is V_TEMP and result.sensor is @config.sensorid
  461. env.logger.debug "<- MySensorDST " , result
  462. @_temperatue = parseFloat(result.value)
  463. @emit "temperature", @_temperatue
  464. )
  465. super()
  466.  
  467. getTemperature: -> Promise.resolve @_temperatue
  468. getBattery: -> Promise.resolve @_batterystat
  469.  
  470. class MySensorsBMP extends env.devices.TemperatureSensor
  471.  
  472. constructor: (@config,lastState, @board) ->
  473. @id = config.id
  474. @name = config.name
  475. @_temperatue = lastState?.temperature?.value
  476. @_pressure = lastState?.pressure?.value
  477. @_forecast = lastState?.forecast?.value
  478. @_batterystat = lastState?.batterystat?.value
  479. env.logger.info "MySensorsBMP " , @id , @name
  480.  
  481. @attributes = {}
  482.  
  483. @attributes.temperature = {
  484. description: "the messured temperature"
  485. type: "number"
  486. unit: '°C'
  487. acronym: 'T'
  488. }
  489.  
  490. @attributes.pressure = {
  491. description: "the messured pressure"
  492. type: "number"
  493. unit: 'hPa'
  494. acronym: 'mbar'
  495. }
  496.  
  497. @attributes.forecast = {
  498. description: "the forecast"
  499. type: "string"
  500. }
  501.  
  502. @attributes.battery = {
  503. description: "Display the Battery level of Sensor"
  504. type: "number"
  505. unit: '%'
  506. acronym: 'BATT'
  507. hidden: !@config.batterySensor
  508. }
  509.  
  510.  
  511. @board.on("rfbattery", (result) =>
  512. if result.sender is @config.nodeid
  513. unless result.value is null or undefined
  514. # When the battery is to low, battery percentages higher then 100 could be send
  515. if result.value > 100
  516. result.value = 0
  517.  
  518. @_batterystat = parseInt(result.value)
  519. @emit "battery" , @_batterystat
  520. )
  521.  
  522. @board.on("rfValue", (result) =>
  523. if result.sender is @config.nodeid
  524. for sensorid in @config.sensorid
  525. if result.sensor is sensorid
  526. env.logger.info "<- MySensorBMP " , result
  527. if result.type is V_TEMP
  528. #env.logger.info "temp" , result.value
  529. @_temperatue = parseInt(result.value)
  530. @emit "temperature", @_temperatue
  531. if result.type is V_PRESSURE
  532. #env.logger.info "pressure" , result.value
  533. @_pressure = parseInt(result.value)
  534. @emit "pressure", @_pressure
  535. if result.type is V_FORECAST
  536. #env.logger.info "forecast" , result.value
  537. @_forecast = result.value
  538. @emit "forecast", @_forecast
  539.  
  540. )
  541. super()
  542.  
  543. getTemperature: -> Promise.resolve @_temperatue
  544. getPressure: -> Promise.resolve @_pressure
  545. getForecast: -> Promise.resolve @_forecast
  546. getBattery: -> Promise.resolve @_batterystat
  547.  
  548. class MySensorsPulseMeter extends env.devices.Device
  549.  
  550. constructor: (@config,lastState, @board) ->
  551. @id = config.id
  552. @name = config.name
  553. @voltage = config.appliedVoltage
  554.  
  555. @_watt = lastState?.watt?.value
  556. @_ampere = lastState?.ampere?.value
  557. @_kwh = lastState?.kWh?.value
  558. @_pulsecount = lastState?.pulsecount?.value
  559. @_batterystat = lastState?.batterystat?.value
  560.  
  561. env.logger.info "MySensorsPulseMeter " , @id , @name
  562.  
  563. @attributes = {}
  564.  
  565. @attributes.watt = {
  566. description: "the messured Wattage"
  567. type: "number"
  568. unit: 'W'
  569. acronym: 'Watt'
  570. }
  571.  
  572. @attributes.pulsecount = {
  573. description: "Measure the Pulse Count"
  574. type: "number"
  575. #unit: ''
  576. hidden: yes
  577. }
  578.  
  579. @attributes.kWh = {
  580. description: "the messured kWh"
  581. type: "number"
  582. unit: 'kWh'
  583. acronym: 'kWh'
  584. }
  585.  
  586. calculatekwh = ( =>
  587. @_avgkw = @_totalkw / @_tickcount
  588. @_kwh = (@_avgkw * (@_tickcount * 10)) / 3600
  589. @_tickcount = 0
  590. @_totalkw = 0
  591. env.logger.info "calculatekwh.." , @kwh
  592. @emit "kWh", @_kwh
  593. )
  594.  
  595.  
  596. @attributes.battery = {
  597. description: "Display the Battery level of Sensor"
  598. type: "number"
  599. unit: '%'
  600. acronym: 'BATT'
  601. hidden: !@config.batterySensor
  602. }
  603.  
  604. @attributes.ampere = {
  605. description: "the messured Ampere"
  606. type: "number",
  607. unit: "A"
  608. acronym: 'Ampere'
  609. }
  610.  
  611. @board.on("rfRequest", (result) =>
  612. if result.sender is @config.nodeid
  613. datas = {}
  614. datas =
  615. {
  616. "destination": @config.nodeid,
  617. "sensor": @config.sensorid,
  618. "type" : V_VAR1,
  619. "value" : @_pulsecount,
  620. "ack" : 1
  621. }
  622. @board._rfWrite(datas)
  623. )
  624.  
  625. @board.on("rfbattery", (result) =>
  626. if result.sender is @config.nodeid
  627. unless result.value is null or undefined
  628. # When the battery is to low, battery percentages higher then 100 could be send
  629. if result.value > 100
  630. result.value = 0
  631.  
  632. @_batterystat = parseInt(result.value)
  633. @emit "battery" , @_batterystat
  634. )
  635.  
  636. @board.on("rfValue", (result) =>
  637. if result.sender is @config.nodeid
  638. if result.sensor is @config.sensorid
  639. env.logger.debug "<- MySensorsPulseMeter" , result
  640. if result.type is V_VAR1
  641. env.logger.debug "<- MySensorsPulseMeter V_VAR1"
  642. @_pulsecount = parseInt(result.value)
  643. @emit "pulsecount", @_pulsecount
  644. if result.type is V_WATT
  645. env.logger.debug "<- MySensorsPulseMeter V_WATT"
  646. @_watt = parseInt(result.value)
  647. @emit "watt", @_watt
  648. @_ampere = @_watt / @voltage
  649. @emit "ampere", @_ampere
  650. if result.type is V_KWH
  651. env.logger.debug "<- MySensorsPulseMeter V_KWH"
  652. @_kwh = parseFloat(result.value)
  653. @emit "kWh", @_kwh
  654.  
  655. )
  656. super()
  657.  
  658. getWatt: -> Promise.resolve @_watt
  659. getPulsecount: -> Promise.resolve @_pulsecount
  660. getKWh: -> Promise.resolve @_kwh
  661. getBattery: -> Promise.resolve @_batterystat
  662. getAmpere: -> Promise.resolve @_ampere
  663.  
  664. class MySensorsPIR extends env.devices.PresenceSensor
  665.  
  666. constructor: (@config,lastState,@board) ->
  667. @id = config.id
  668. @name = config.name
  669. @_presence = lastState?.presence?.value or false
  670. env.logger.info "MySensorsPIR " , @id , @name, @_presence
  671.  
  672. resetPresence = ( =>
  673. @_setPresence(no)
  674. )
  675.  
  676. @board.on('rfValue', (result) =>
  677. if result.sender is @config.nodeid and result.type is V_TRIPPED and result.sensor is @config.sensorid
  678. env.logger.info "<- MySensorPIR ", result
  679. if result.value is ZERO_VALUE
  680. @_setPresence(no)
  681. else
  682. @_setPresence(yes)
  683. if @config.autoReset is true
  684. clearTimeout(@_resetPresenceTimeout)
  685. @_resetPresenceTimeout = setTimeout(( =>
  686. @_setPresence(no)
  687. ), @config.resetTime)
  688. )
  689.  
  690. super()
  691.  
  692. getPresence: -> Promise.resolve @_presence
  693.  
  694. class MySensorsButton extends env.devices.ContactSensor
  695.  
  696. constructor: (@config,lastState,@board) ->
  697. @id = config.id
  698. @name = config.name
  699. @_contact = lastState?.contact?.value or false
  700. env.logger.info "MySensorsButton" , @id , @name, @_contact
  701.  
  702. @attributes = _.cloneDeep @attributes
  703.  
  704. @attributes.battery = {
  705. description: "Display the Battery level of Sensor"
  706. type: "number"
  707. unit: '%'
  708. acronym: 'BATT'
  709. hidden: !@config.batterySensor
  710. }
  711.  
  712. @board.on("rfbattery", (result) =>
  713. if result.sender is @config.nodeid
  714. unless result.value is null or undefined
  715. # When the battery is to low, battery percentages higher then 100 could be send
  716. if result.value > 100
  717. result.value = 0
  718.  
  719. @_batterystat = parseInt(result.value)
  720. @emit "battery" , @_batterystat
  721. )
  722.  
  723. @board.on('rfValue', (result) =>
  724. if result.sender is @config.nodeid and result.type is ( V_TRIPPED or V_STATUS ) and result.sensor is @config.sensorid
  725. env.logger.info "<- MySensorsButton ", result
  726. if result.value is ZERO_VALUE
  727. @_setContact(yes)
  728. else
  729. @_setContact(no)
  730. )
  731. super()
  732.  
  733. getBattery: -> Promise.resolve @_batterystat
  734.  
  735. class MySensorsSwitch extends env.devices.PowerSwitch
  736.  
  737. constructor: (@config,lastState,@board) ->
  738. @id = config.id
  739. @name = config.name
  740. @_state = lastState?.state?.value
  741. env.logger.info "MySensorsSwitch " , @id , @name, @_state
  742.  
  743. @board.on('rfValue', (result) =>
  744. if result.sender is @config.nodeid and result.type is V_STATUS and result.sensor is @config.sensorid
  745. state = (if parseInt(result.value) is 1 then on else off)
  746. env.logger.info "<- MySensorSwitch " , result
  747. @_setState(state)
  748. )
  749. super()
  750.  
  751. changeStateTo: (state) ->
  752. assert state is on or state is off
  753. if state is true then _state = 1 else _state = 0
  754. datas = {}
  755. datas =
  756. {
  757. "destination": @config.nodeid,
  758. "sensor": @config.sensorid,
  759. "type" : V_STATUS,
  760. "value" : _state,
  761. "ack" : 1
  762. }
  763. @board._rfWrite(datas).then ( () =>
  764. @_setState(state)
  765. )
  766.  
  767. class MySensorsDimmer extends env.devices.DimmerActuator
  768. _lastdimlevel: null
  769.  
  770. constructor: (@config, lastState, @board) ->
  771. @id = config.id
  772. @name = config.name
  773. @_dimlevel = lastState?.dimlevel?.value or 0
  774. @_lastdimlevel = lastState?.lastdimlevel?.value or 100
  775. @_state = lastState?.state?.value or off
  776.  
  777. @board.on('rfValue', (result) =>
  778. if result.sender is @config.nodeid and result.type is V_PERCENTAGE and result.sensor is @config.sensorid
  779. state = (if parseInt(result.value) is 0 then off else on)
  780. dimlevel = (result.value)
  781. env.logger.info "<- MySensorDimmer " , result
  782. @_setState(state)
  783. @_setDimlevel(dimlevel)
  784. )
  785. super()
  786.  
  787. turnOn: -> @changeDimlevelTo(@_lastdimlevel)
  788.  
  789. changeDimlevelTo: (level) ->
  790. unless @config.forceSend
  791. if @_dimlevel is level then return Promise.resolve true
  792. if level is 0
  793. state = false
  794. unless @_dimlevel is 0
  795. @_lastdimlevel = @_dimlevel
  796. datas = {}
  797. datas =
  798. {
  799. "destination": @config.nodeid,
  800. "sensor": @config.sensorid,
  801. "type" : V_PERCENTAGE,
  802. "value" : level,
  803. "ack" : 1
  804. }
  805. @board._rfWrite(datas).then ( () =>
  806. @_setDimlevel(level)
  807. )
  808.  
  809. class MySensorsLight extends env.devices.Device
  810.  
  811. constructor: (@config,lastState, @board) ->
  812. @id = config.id
  813. @name = config.name
  814.  
  815. @_light = lastState?.light?.value
  816. @_batterystat = lastState?.batterystat?.value
  817. env.logger.info "MySensorsLight " , @id , @name
  818. @attributes = {}
  819.  
  820. @attributes.battery = {
  821. description: "display the Battery level of Sensor"
  822. type: "number"
  823. unit: '%'
  824. acronym: 'BATT'
  825. hidden: !@config.batterySensor
  826. }
  827.  
  828. @board.on("rfbattery", (result) =>
  829. if result.sender is @config.nodeid
  830. unless result.value is null or undefined
  831. # When the battery is to low, battery percentages higher then 100 could be send
  832. if result.value > 100
  833. result.value = 0
  834.  
  835. @_batterystat = parseInt(result.value)
  836. @emit "battery" , @_batterystat
  837. )
  838.  
  839. @attributes.light = {
  840. description: "the messured light"
  841. type: "number"
  842. unit: '%'
  843. }
  844.  
  845. @board.on("rfValue", (result) =>
  846. if result.sender is @config.nodeid
  847. if result.sensor is @config.sensorid
  848. env.logger.info "<- MySensorsLight" , result
  849. if result.type is V_LIGHT_LEVEL
  850. @_light = parseInt(result.value)
  851. @emit "light", @_light
  852. )
  853. super()
  854.  
  855. getLight: -> Promise.resolve @_light
  856. getBattery: -> Promise.resolve @_batterystat
  857.  
  858. class MySensorsLux extends env.devices.Device
  859.  
  860. constructor: (@config,lastState, @board) ->
  861. @id = config.id
  862. @name = config.name
  863.  
  864. @_lux = lastState?.lux?.value
  865. @_batterystat = lastState?.batterystat?.value
  866. #env.logger.info "MySensorsLux " , @id , @name
  867. @attributes = {}
  868.  
  869.  
  870. @attributes.battery = {
  871. description: "display the Battery level of Sensor"
  872. type: "number"
  873. unit: '%'
  874. acronym: 'BATT'
  875. hidden: !@config.batterySensor
  876. }
  877.  
  878. @board.on("rfbattery", (result) =>
  879. if result.sender is @config.nodeid
  880. unless result.value is null or undefined
  881. @_batterystat = parseInt(result.value)
  882. @emit "battery" , @_batterystat
  883. )
  884.  
  885.  
  886. @attributes.lux = {
  887. description: "the messured light in lux"
  888. type: "number"
  889. unit: 'lux'
  890. }
  891.  
  892. @board.on("rfValue", (result) =>
  893. if result.sender is @config.nodeid
  894. if result.sensor is @config.sensorid
  895. env.logger.info "<- MySensorsLux" , result
  896. if result.type is V_LIGHT_LEVEL or V_LEVEL
  897. @_lux = parseInt(result.value)
  898. @emit "lux", @_lux
  899. )
  900. super()
  901.  
  902. getLux: -> Promise.resolve @_lux
  903. getBattery: -> Promise.resolve @_batterystat
  904.  
  905. class MySensorsDistance extends env.devices.Device
  906.  
  907. constructor: (@config,lastState, @board) ->
  908. @id = config.id
  909. @name = config.name
  910. @_distance= lastState?.distance?.value
  911. @_batterystat = lastState?.batterystat?.value
  912. env.logger.info "MySensorsDistance " , @id , @name
  913. @attributes = {}
  914.  
  915. @attributes.battery = {
  916. description: "display the Battery level of Sensor"
  917. type: "number"
  918. unit: '%'
  919. acronym: 'BATT'
  920. hidden: !@config.batterySensor
  921. }
  922.  
  923. @board.on("rfbattery", (result) =>
  924. if result.sender is @config.nodeid
  925. unless result.value is null or undefined
  926. # When the battery is to low, battery percentages higher then 100 could be send
  927. if result.value > 100
  928. result.value = 0
  929.  
  930. @_batterystat = parseInt(result.value)
  931. @emit "battery" , @_batterystat
  932. )
  933.  
  934. @attributes.distance = {
  935. description: "the messured distance"
  936. type: "number"
  937. unit: 'cm'
  938. }
  939.  
  940. @board.on("rfValue", (result) =>
  941. if result.sender is @config.nodeid
  942. if result.sensor is @config.sensorid
  943. env.logger.info "<- MySensorsDistance" , result
  944. if result.type is V_DISTANCE
  945. @_distance = parseInt(result.value)
  946. @emit "distance", @_distance
  947. )
  948. super()
  949.  
  950. getDistance: -> Promise.resolve @_distance
  951. getBattery: -> Promise.resolve @_batterystat
  952.  
  953. class MySensorsGas extends env.devices.Device
  954.  
  955. constructor: (@config,lastState, @board) ->
  956. @id = config.id
  957. @name = config.name
  958. @_gas = lastState?.gas?.value
  959. @_batterystat = lastState?.batterystat?.value
  960. env.logger.info "MySensorsGas " , @id , @name
  961. @attributes = {}
  962.  
  963. @attributes.battery = {
  964. description: "display the Battery level of Sensor"
  965. type: "number"
  966. unit: '%'
  967. acronym: 'BATT'
  968. hidden: !@config.batterySensor
  969. }
  970.  
  971. @board.on("rfbattery", (result) =>
  972. if result.sender is @config.nodeid
  973. unless result.value is null or undefined
  974. # When the battery is to low, battery percentages higher then 100 could be send
  975. if result.value > 100
  976. result.value = 0
  977.  
  978. @_batterystat = parseInt(result.value)
  979. @emit "battery" , @_batterystat
  980. )
  981.  
  982. @attributes.gas = {
  983. description: "the messured gas presence in ppm"
  984. type: "number"
  985. unit: 'ppm'
  986. }
  987.  
  988. @board.on("rfValue", (result) =>
  989. if result.sender is @config.nodeid
  990. if result.sensor is @config.sensorid
  991. env.logger.info "<- MySensorsGas" , result
  992. if result.type is V_VAR1
  993. @_gas = parseInt(result.value)
  994. @emit "gas", @_gas
  995. )
  996. super()
  997.  
  998. getGas: -> Promise.resolve @_gas
  999. getBattery: -> Promise.resolve @_batterystat
  1000.  
  1001. class MySensorsMulti extends env.devices.Device
  1002.  
  1003. constructor: (@config,lastState, @board) ->
  1004. @id = config.id
  1005. @name = config.name
  1006.  
  1007. @attributeValue = {}
  1008. @attributes = {}
  1009. # loop trough all attributes in the config and initialise all attributes
  1010. for attr, i in @config.attributes
  1011. do (attr) =>
  1012. name = attr.name
  1013. @attributes[name] = {
  1014. description: name
  1015. unit : attr.unit
  1016. acronym: attr.acronym
  1017. label : attr.label
  1018. }
  1019. switch attr.type
  1020. when "integer"
  1021. @attributes[name].type = "number"
  1022. when "float"
  1023. @attributes[name].type = "number"
  1024. when "round"
  1025. @attributes[name].type = "number"
  1026. when "boolean"
  1027. @attributes[name].type = "boolean"
  1028. if _.isArray attr.booleanlabels
  1029. @attributes[name].labels = attr.booleanlabels
  1030. when "string"
  1031. @attributes[name].type = "string"
  1032. when "battery"
  1033. @attributes[name].type = "number"
  1034. else
  1035. throw new Error("Illegal unit for attribute type: #{name} in MySensorsMulti.")
  1036.  
  1037. @attributeValue[name] = lastState?[name]?.value
  1038. @_createGetter name, ( => Promise.resolve @attributeValue[name] )
  1039.  
  1040. # when a mysensors value has been received
  1041. @board.on("rfValue", (result) =>
  1042. # loop trough all attributes in the config
  1043. for attr, i in @config.attributes
  1044. do (attr) =>
  1045. name = attr.name
  1046. # check if the received nodeid and sensorid are the same as the nodeid and sensorid in the config of the attribute
  1047. if result.sender is attr.nodeid and result.sensor is attr.sensorid
  1048. receiveData = false
  1049. # if a sensortype has been provided
  1050. if attr.sensortype?
  1051. # check if the received sensortype is the same as the sensortype in the config of the attribute
  1052. if result.type is attr.sensortype
  1053. receiveData = true
  1054. else
  1055. receiveData = true
  1056.  
  1057. if (receiveData)
  1058. env.logger.debug "<- MySensorsMulti" , result
  1059. # Adjust the received value according to the type that has been set in the config
  1060. switch attr.type
  1061. when "integer"
  1062. value = parseInt(result.value)
  1063. when "float"
  1064. value = parseFloat(result.value)
  1065. when "round"
  1066. value = Math.round(parseFloat(result.value))
  1067. when "boolean"
  1068. if result.value is "0"
  1069. value = false
  1070. else
  1071. value = true
  1072. when "string"
  1073. value = result.value
  1074. when "battery"
  1075. # You should not set a sensorid for a battery sensor
  1076. throw new Error("A battery doesn't need a sensorid: #{name} in MySensorsMulti.")
  1077. else
  1078. throw new Error("Illegal unit for attribute type: #{name} in MySensorsMulti.")
  1079.  
  1080. # If the received value is different then the current value, it should be emitted
  1081. @_setAttribute name, value
  1082. )
  1083.  
  1084. # when a battery percentage has been received
  1085. @board.on("rfbattery", (result) =>
  1086. # loop trough all attributes in the config
  1087. for attr, i in @config.attributes
  1088. do (attr) =>
  1089. name = attr.name
  1090. type = attr.type
  1091. # if the attribute has a type of battery and the received nodeid is the same as the nodeid in the config of the attribute
  1092. if result.sender is attr.nodeid and type is "battery"
  1093. unless result.value is null or undefined
  1094. env.logger.debug "<- MySensorsMulti" , result
  1095. # When the battery is to low, battery percentages higher then 100 could be send
  1096. if result.value > 100
  1097. result.value = 0
  1098. value = parseInt(result.value)
  1099. # If the received value is different then the current value, it should be emitted
  1100. @_setAttribute name, value
  1101. )
  1102. super()
  1103.  
  1104. _setAttribute: (attributeName, value) ->
  1105. unless @attributeValue[attributeName] is value
  1106. @attributeValue[attributeName] = value
  1107. @emit attributeName, value
  1108.  
  1109. class MySensorsBattery extends env.devices.Device
  1110.  
  1111. constructor: (@config,lastState, @board,@framework) ->
  1112. @id = config.id
  1113. @name = config.name
  1114. env.logger.info "MySensorsBattery" , @id , @name
  1115.  
  1116. @attributes = {}
  1117. @_batterystat = {}
  1118. for nodeid in @config.nodeid
  1119. do (nodeid) =>
  1120. for device in @framework.deviceManager.devicesConfig
  1121. if device?.nodeid and device?.nodeid is nodeid
  1122. attrname = device?.name
  1123. break
  1124.  
  1125. attr = "batteryLevel_" + nodeid
  1126. @attributes[attr] = {
  1127. description: "the measured Battery Stat of Sensor"
  1128. type: "number"
  1129. unit: '%'
  1130. acronym: attrname
  1131. }
  1132. getter = ( => Promise.resolve @_batterystat[nodeid] )
  1133. @_createGetter( attr, getter)
  1134. @_batterystat[nodeid] = lastState?[attr]?.value
  1135.  
  1136. @board.on("rfbattery", (result) =>
  1137. unless result.value is null or undefined
  1138. # When the battery is to low, battery percentages higher then 100 could be send
  1139. if result.value > 100
  1140. result.value = 0
  1141.  
  1142. @_batterystat[result.sender] = parseInt(result.value)
  1143. @emit "batteryLevel_" + result.sender, @_batterystat[result.sender]
  1144. )
  1145. super()
  1146.  
  1147. class MySensorsActionHandler extends env.actions.ActionHandler
  1148.  
  1149. constructor: (@framework,@board,@nodeid,@sensorid,@cmdcode,@customvalue) ->
  1150.  
  1151. executeAction: (simulate) =>
  1152. Promise.all( [
  1153. @framework.variableManager.evaluateStringExpression(@nodeid)
  1154. @framework.variableManager.evaluateStringExpression(@sensorid)
  1155. @framework.variableManager.evaluateStringExpression(@cmdcode)
  1156. @framework.variableManager.evaluateStringExpression(@customvalue)
  1157. ]).then( ([node, sensor, code ,customvalue]) =>
  1158. if simulate
  1159. # just return a promise fulfilled with a description about what we would do.
  1160. return __("would send IR \"%s\"", cmdCode)
  1161. else
  1162. datas = {}
  1163.  
  1164. switch customvalue
  1165. when "V_VAR1"
  1166. type_value = V_VAR1
  1167. when "V_VAR2"
  1168. type_value = V_VAR2
  1169. when "V_VAR3"
  1170. type_value = V_VAR3
  1171. when "V_VAR4"
  1172. type_value = V_VAR4
  1173. when "V_VAR5"
  1174. type_value = V_VAR5
  1175. when "V_DIMMER"
  1176. type_value = V_DIMMER
  1177. when "V_LIGHT"
  1178. type_value = V_LIGHT
  1179. else
  1180. type_value = V_IR_SEND
  1181. datas =
  1182. {
  1183. "destination": node,
  1184. "sensor": sensor,
  1185. "type" : type_value,
  1186. "value" : code,
  1187. "ack" : 1
  1188. }
  1189. return @board._rfWrite(datas).then ( () =>
  1190. __("IR message sent successfully")
  1191. )
  1192. )
  1193.  
  1194. class MySensorsActionProvider extends env.actions.ActionProvider
  1195.  
  1196. constructor: (@framework,@board) ->
  1197.  
  1198. parseAction: (input, context) =>
  1199.  
  1200. cmdcode = "0x00000"
  1201. nodeid = "0"
  1202. sensorid = "0"
  1203. fullMatch = no
  1204. CustomValue = "V_IR_SEND"
  1205.  
  1206. setTypeValue = (m, tokens) => CustomValue = tokens
  1207. setCmdcode = (m, tokens) => cmdcode = tokens
  1208. setSensorid = (m, tokens) => sensorid = tokens
  1209. setNodeid = (m, tokens) => nodeid = tokens
  1210.  
  1211. onEnd = => fullMatch = yes
  1212.  
  1213. m = M(input, context)
  1214. .match('send ')
  1215. .match('custom ').matchStringWithVars(setTypeValue)
  1216.  
  1217. next = m.match(' nodeid: ').matchStringWithVars(setNodeid)
  1218. if next.hadMatch() then m = next
  1219.  
  1220. next = m.match(' sensorid: ').matchStringWithVars(setSensorid)
  1221. if next.hadMatch() then m = next
  1222.  
  1223. next = m.match(' cmdcode: ').matchStringWithVars(setCmdcode)
  1224. if next.hadMatch() then m = next
  1225.  
  1226. if m.hadMatch()
  1227. match = m.getFullMatch()
  1228. return {
  1229. token: match
  1230. nextInput: input.substring(match.length)
  1231. actionHandler: new MySensorsActionHandler(@framework,@board,nodeid,sensorid,cmdcode,CustomValue)
  1232. }
  1233. else
  1234. return null
  1235.  
  1236. # ###Finally
  1237. # Create a instance of my plugin
  1238. mySensors = new MySensors
  1239. # and return it to the framework.
  1240. return mySensors
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement