enocean-js / node-enocean

an enocean implementation for node.js
GNU General Public License v2.0
29 stars 14 forks source link

New eep A5-20-01 #44

Open Jean-PhilippeD opened 5 years ago

Jean-PhilippeD commented 5 years ago

Hello,

I've just bought a new ubiwizz device which isa self-powered iTRV.

I've pushed as you described in the README the new eep in enocean eepResolver but I have no idea how to parse data received.

here it is whatis print when I try to learn the device :


  timestamp: 1544043543857,
  loadFromBuffer: [Function],
  rawByte: '55000a0701eba500307f08050ac9f60001ffffffff5f00da',
  packetType: 1,
  senderId: '050ac9f6',
  choice: 'a5',
  subTelNum: 1,
  destinationId: 'ffffffff',
  rssi: 95,
  securityLevel: 0,
  packetTypeString: '4BS',
  raw: '00307f08',
  learnBit: 1,
  sensor: 
   { id: '050ac9f6',
     eep: 'a5-20-01',
     title: 'New HVAC Components',
     desc: 'I\'m a new sensor...',
     eepFunc: 'HVAC Components',
     eepType: 'Battery Powerd Actuator (BI-DIR)' },
  values: { type: 'Battery Powerd Actuator (BI-DIR', value: '00307f08' },
  data: 
   { LRNB: 
      { name: 'LRN Bit',
        value: 1,
        desc: 'Data telegram',
        unit: undefined },
     SP: 
      { name: 'Valve position or Temperature Setpoint',
        value: NaN,
        unit: '% or °C' },
     TMP: 
      { name: 'Temperature  from RCU',
        value: 32.470588235294116,
        unit: '°C' },
     SPS: 
      { name: 'Set Point Selection',
        value: 1,
        desc: 'Temperature set point 0...40°C. Unit respond to room sensor and use internal PI loop.',
        unit: undefined },
     RCU: 
      { name: 'Select function',
        value: 1,
        desc: 'service on',
        unit: undefined } } }

Do you think you could help me to bring this device alive ? :)

Holger-Will commented 5 years ago

I'm currently in the middle of a complete rewrite of node-enocean, making it more modular and easier to use. Working with the old version, the new version will definitely not be backwards compatible and ultimately break the code you write right now.

It seems like it is allready tought in correctly. What exactly do you want to do and what does your code look like so far?

Jean-PhilippeD commented 5 years ago

Hi,

I've just used this code:

enocean.eepResolvers.push(function(eep,data){ if(eep==="a5-20-01") { return { type:"Battery Powerd Actuator (BI-DIR)",value: data } } return null })

I would like to be able to parse the data and send action. I have no idea how to parse this value : 00307f08

Holger-Will commented 5 years ago

you don't need to push your own resolver because a5-20-01 is allready supported out of the box. the bit is the already parsed content:

data: 
  { LRNB: 
    { name: 'LRN Bit',
      value: 1,
      desc: 'Data telegram',
      unit: undefined },
   SP: 
    { name: 'Valve position or Temperature Setpoint',
      value: NaN,
      unit: '% or °C' },
   TMP: 
    { name: 'Temperature  from RCU',
      value: 32.470588235294116,
      unit: '°C' },
   SPS: 
    { name: 'Set Point Selection',
      value: 1,
      desc: 'Temperature set point 0...40°C. Unit respond to room sensor and use internal PI loop.',
      unit: undefined },
   RCU: 
    { name: 'Select function',
      value: 1,
      desc: 'service on',
      unit: undefined } } }

packet content is specified in the Enocean Equipment Profile Specification (EEP)

Jean-PhilippeD commented 5 years ago

Thanks for the tips but I stil have no idea how to send any command to the device :( I don't know how to forge the raw value I need to send.

Holger-Will commented 5 years ago

ohhhh, ok. sorry. misunderstood. yes i can help you bringing it into life. the current state of node-enocean however is so bad that you might have to wait for the rewrite...

sending data is a bit more involved... but i realize that the current resolver is also broken, so:

I have no idea how to parse this value : 00307f08

ok, so these are the 4 Bytes of data send in a 4BS Telegram. so split this value in 4 Bytes

byte3 = parseInt("00",16)
byte2 = parseInt("03",16)
byte1 = parseInt("7f",16)
byte0 = parseInt("08",16) // you wont need this one (in case a5-20-01) it's only use to tell if it's a learn telegram or not. 08 means data telegram.

In the case actuator to controller:

byte3 is the current valve position.

byte1 is the temperature where 0x00 to 0xff map to 0 to 40 degrees

which maps to (byte1/255)*40 = 20°C (byte1 = 0x7f = 127)

byte2 contains some bits. "03" written in binary: 0b00000011 this means "detector window open" and "actuator obstructed"

shorname bit meaning
SO 7 Service On
ENIE 6 Energy input enabled
ES 5 Energy storage insufficiently charged
BCAP 4 Battery capacity: change next days
CCO 3 contact cover open
FTS 2 failure: temperature sensor out of range
DWO 1 detector window open
ACO 0 actuator obstructed

so your resolver may look like this:

enocean.eepResolvers.push(function(eep,data){
  if(eep==="a5-20-01") {
    function isBitSet (num, bitnum) {
      var mask = Math.pow(2, bitnum)
      return (num & mask) == mask
    }
    var byte3 = parseInt(data.substr(0, 2), 16)
    var byte2 = parseInt(data.substr(2, 2), 16)
    var byte1 = parseInt(data.substr(4, 2), 16)
    return {
      type: 'Battery Powerd Actuator (BI-DIR)',
      valve_position: byte3,
      temperature: byte1 / 255 * 40,
      SO: isBitSet(byte2, 7),
      ENIE: isBitSet(byte2, 6),
      ES: isBitSet(byte2, 5),
      BCAP: isBitSet(byte2, 4),
      CCO: isBitSet(byte2, 3),
      FTS: isBitSet(byte2, 2),
      DWO: isBitSet(byte2, 1),
      ACO: isBitSet(byte2, 0)   
    }
  }
  return null
})

let me know if this works... then we can turn to sending data to the actuator

Holger-Will commented 5 years ago

Data Telegram

generating the payload

again byte0 is "08" data telegram. composing a teach in telegram is a different matter... more on that later byte1 again holds some bits:

shorname bit meaning desc
RIN 7 run init sequence The limit switching measures the travel and signals when an end position has been reached. This end position (valve zero point) in the actuator is stored.
LFS 6 Lift set Initialization, adjustment to the valve stroke. The Initialization is switched after receiving the command. The valve is completely opened and closed during initialization.
VO 5 Valve Open / maintainace After receiving an operation command, the actuator moves the valve in direction open or close.\nwhen reaching the end position, an automatic switch-off procedure is started. In service mode the valve\ncan be set to open or closed always.
VC 4 valve closed
SB 3 summer bit / reduction of energy consumption The radio communication between the actuator and the controller is restricted, sleep mode is extended. This functionality can be used for battery powered actuators.
SPS 2 setpoint selection 0: Valve position (0-100%). Unit respond to controller. 1: Temperature set point 0...40°C. Unit respond to room sensor and use internal PI loop.
SPN 1 setoint inverse Valve set point can be sent to the actuator normal or inverted.\nThe selection is done by DB_1.Bit1. The implementation is done and is controlled in the actuator with DB_3. This function is used in dependence on the type of valve.
RCU 0 function select RCU (0) or 'Service on' (1): After transmitting the command to the actuator, it can be send from the controller or a\nservice device, the actuator sends a status feedback signal (service on, DB_2.BIT_7).

for setting these bits you can write the bit positions in binary and store it somewhere, and when you want to activate a bit just add the value:

var bits = {
  RIN: 0b10000000,
  LFS: 0b01000000,
  VO: 0b00100000,
  VC: 0b00010000,
  SB: 0b00001000,
  SPS: 0b00000100,
  SPN: 0b00000010,
  RCU: 0b00000001
}

byte1 = bits.SPS + bits.SPN //etc

byte3

Valve position or Temperature set point (linear); selection with byte1 bit 2

if byte1 bit 2 is 0, byte3 can be between 0 and 100 (Valve position)

byte3 = 73 // open valve 73%

if byte1 bit 2 is set, you can send a temperature setpoint wich again should be maped from 0-255 to 0-40so to set the temperature to x degrees:

byte3 = x / 40 * 255

byte2

with byte2 you can send an actual temperature. if you have a room control unit(RCU) and you want to use its temperature set byte2 to 0. If you don't have an RCU or want overwrite its value, send a temperature. Be carefull, here the mapping is reversed. a value of 255 means 0 °C and a value of 0 means 40 °C.

byte2 = (40 - x) / 40 * 255

if you have that, you can combine these bytes

var payload = Buffer.from([byte3,byte2,byte1,byte0])

telegram construction

now we have to construct the telegram. first we construct the data part, for this we need the RORG wich is 0xa5 in our case. then we need the base address of our TCM300 USB Stick. node-enocean should have requested and stored it for you already. youn can get it with enocean.base. you can simulate up to 127 devices with one usb stick. for this you can add a device offset to the base address, to get a unique id.

var deviceOffset = 1
var deviceId = (parseInt(enocean.base,16) + deviceOffset)

now we can combine all this to the data part of our telegram:

var data = `a5${payload.toString('hex')}${deviceid}00`

now we need the optional data. in this case we don't need to calculate anything for this. its:

 var optionalData = "03ffffffffff00"

now we have to pack oll this to an actual telegram. use the code from this gist https://gist.github.com/Holger-Will/18ae06a997a83c54cd9fe2407650012d

var packet = pack(Buffer.from(data,"hex),1,Buffer.from(optionalData,"hex"))

now we are ready to send.

enocean.write(packet)

But this will most likely not work :-( because we have to first generate a teach in telegram to teach our valve about our virtual device.

var data = `a58008fe80${deviceid}00`
var optionalData = "03ffffffffff00"
var packet = pack(Buffer.from(data,"hex),1,Buffer.from(optionalData))
enocean.write(packet)

now we are good to go, set your actuator to learn mode, send the teach in telegram, and after that you can control your valve from your computer ;-) (p.s.: you have to send the teach in only once...)

the whole process will be much much much simpler with the next version... there is still a lot to do though, it would be fantastic if you would be willing to help. any help is greatly appreciated!

Jean-PhilippeD commented 5 years ago

Big thanks for all those informations !

I better understand how building packets is working now. I'm trying to implement it in the module I write for Gladys Project but I still have a few question regarding this device ..

Should I always send bytes1 if I want to just send a new temperature set point (bytes3) ? If so, it means I have to remember the last values I've set on bytes1 ... i'm a bit consufed.

Moreover, I didn't understood the purpose of RCU values and how is it working..

Thanks again, I have been able to implement the first part, the communication from the device to the controller by the way :)

Edit:

Ok I think I understand.

In fact, each time I send a packet, I need to send the whole configuration, I can not just update a "field"