Giter Club home page Giter Club logo

cul's Introduction

cul

NPM version dependencies Status Build Status XO code style License

This is a Node.js module that can be used to interact with a Busware CUL (USB), COC (RaspberryPi), SCC (RaspberryPi) or CUNO running culfw. With CUL/COC/SCC/CUNO and culfw many RF devices can be controlled, like FS20, MAX!, temperature sensors, weather stations and more. See the full list of supported Devices.

Purpose

This module provides a thin abstraction for the serial port or telnet communication with CUL/COC/SCC/CUNO/CUNO2 and lightweight parse and command wrappers. It's intended to be used in different Node.js based Home Automation software.

Credits

based on the work of Rudolf Koenig, Author of culfw and fhem (both licensed under GPLv2)

Usage

npm install cul

var Cul = require('cul');
var cul = new Cul();

// ready event is emitted after serial connection is established and culfw acknowledged data reporting
cul.on('ready', function () {
    // send arbitrary commands to culfw
    cul.write('V');
});

cul.on('data', function (raw) {
    // show raw incoming messages
    console.log(raw);
});

Options

  • connectionMode (default: "serial") possible values:
    • serial (CUL/COC/SCC)
    • telnet (CUNO/CUNO2)
  • serialport (default: "/dev/ttyAMA0")
  • baudrate (default: 9600)
  • mode (default: "SlowRF")
    possible values:
    • SlowRF (FS20, HMS, FHT, EM, ...)
    • MORITZ (MAX! devices)
    • AskSin (HomeMatic devices)
  • parse (default: true)
    try to parse received messages
  • init (default: true)
    auto send "enable datareporting" command when connection is established (depends on chosen mode)
  • coc (default: false)
    has to be enabled for usage with COC), changes default baudrate to 38400 and default serialport to /dev/ttyACM0
  • scc (default: false)
    has to be enabled for usage with SCC), changes default baudrate to 38400 and default serialport to /dev/ttyAMA0
  • rssi (default: true)
    receive rssi (signal strength) value with every message (works only if init and parse are both true)
  • debug (default: false)
    log every command which is send in the console
  • repeat (default: false)
    disable repeat message filtering in culfw, that means report each of the (repeated) packets of a message
  • host (no default value)
    the IP-Address of CUNO (has to be set when using telnet mode)
  • port (default: 2323)
    the port of the telnet server
  • networkTimeout (default: true)
    enabling sending keep alive signals to the telnet server

pass options when creating a new cul object:

var Cul = require('cul');
var fs20 = new Cul({
    serialport: '/dev/ttyACM0',
    mode: 'SlowRF'
});
var max = new Cul({
    serialport: '/dev/ttyACM1',
    mode: 'MORITZ'
});

Methods

  • close( )
    close the serialport connection
  • write(raw, callback)
    send message to cul. writes directly to the serialport
    optional callback is passed through to serialport module and is called with params (err, res)
  • cmd(protocol, arg1, arg2, ..., callback)
    generate a command and send it to cul (see chapter "predefined commands" below)
    optional callback is passed through to serialport module and is called with params (err, res)

Events

  • ready
    called when serialport connection is established and (if init is true) datareporting is enabled
  • close
    called when serialport connection is closed
  • data(raw, obj)
    called for every received message
    • raw string, contains the raw message received from cul
    • obj object, contains parsed message data (see "data parsing" below)
  • error(exception)
    called when serialport or tcp connection is returning an error

Sending commands

Raw commands

Example

cul.write('F6C480111'); // Raw command

Predefined commands

(until now only FS20 and FHT is implemented)

FS20

Take a look at the file lib/fs20.js - it exports a function cmd(housecode, address, command, time, bidi, res)

example

cul.cmd('FS20', '2341 2131', '1112', 'on'); // house code in ELV-Notation, address in ELV-Notation, command as text
cul.cmd('FS20', '6C48', '01', '11');        // house code as hex string, address as hex string, command as hex string

(these examples result in the same message as the raw command example above.)

Data parsing

The 2nd param obj of the data event contains a object representation of the parsed data.

Each object has the following attributes:

  • protocol
    FS20, EM, HMS, WS, MORITZ, ...
  • address
    a unique address in this protocol
  • device
    device type name
  • rssi
    radio signal strength value (only present if option rssi is true)
  • data
    a object with the parsed data

Examples

Sample output of

cul.on('data', function (raw, obj) {
    console.log(raw, obj);
});

FS20

F6C480011E5, {
    protocol: 'FS20',
    address: '6C4800',
    device: 'FS20',
    rssi: -87.5,
    data: {
        addressCode: '6C48',
        addressCodeElv: '2341 2131',
        addressDevice: '00',
        addressDeviceElv: '1111',
        extended: false,
        time: null,
        bidirectional: false,
        response: false,
        cmdRaw: '11',
        cmd: 'on'

    }
}

EM1000

E020563037A01000200EC, {
    protocol: 'EM',
    address: '0205',
    device: 'EM1000-EM',
    rssi: -84,
    data: { seq: 99, total: 31235, current: 1, peak: 2 }
}

S300TH

K1145525828, {
    protocol: 'WS',
    address: 1,
    device: 'S300TH',
    rssi: -28,
    data: { temperature: 24.5, humidity: 58.5 },
}

Moritz (MAX!)

V 1.66 CSM868 { data: { culfw: { version: '1.66', hardware: 'CSM868' } },
  protocol: 'MORITZ',
  rssi: -22 }
Z0C000442113AD30C4F0D001CB41D { data:
   { len: 12,
     msgcnt: 0,
     msgFlag: '04',
     msgTypeRaw: '42',
     msgType: 'WallThermostatControl',
     src: '113ad3',
     dst: '0c4f0d',
     groupid: 0,
     payload: '1CB41D',
     desiredTemperature: 14,
     measuredTemperature: 18 },
  protocol: 'MORITZ',
  address: '113ad3',
  device: 'WallMountedThermostat',
  rssi: -59.5 }
Z0E0002020C4F0D113AD3000119001C1E { data:
   { len: 14,
     msgcnt: 0,
     msgFlag: '02',
     msgTypeRaw: '02',
     msgType: 'Ack',
     src: '0c4f0d',
     dst: '113ad3',
     groupid: 0,
     payload: '0119001C1E',
     dstDevice: 'WallMountedThermostat' },
  protocol: 'MORITZ',
  address: '0c4f0d',
  rssi: -59 }
  Z0B4F06300E3F3C1234560012F7 { data:
   { len: 11,
     msgcnt: 79,
     msgFlag: '06',
     msgTypeRaw: '30',
     msgType: 'ShutterContactState',
     src: '0e3f3c',
     dst: '123456',
     groupid: 0,
     payload: '12F7',
     isopen: 1,
     unkbits: 4,
     rferror: 0,
     batterlow: 0,
     battery: 'ok' },
  protocol: 'MORITZ',
  address: '0e3f3c',
  device: 'ShutterContact',
  rssi: -78.5 }

FHT

T4C5300AA00E3 { protocol: 'FHT',
  address: '4c53',
  data:
   { cmdRaw: '00',
     addressCode: 7683,
     cmd: 'actuator',
     valueRaw: '00' },
  rssi: -88.5 }
T4D3F286924E2 { protocol: 'FHT',
  address: '4d3f',
  data:
   { cmdRaw: '28',
     addressCode: 7763,
     cmd: 'sat-from1',
     valueRaw: '24',
     value: '6:00' },
  rssi: -89 }

Until now for these devices data parsing and/or a command wrapper is implemented:

protocol device should work tested
FS20 all Devices
HMS HMS100T
HMS HMS100TF
EM EM1000(-EM, -GZ, -WZ)
WS S300TH
MORITZ HeatingThermostat
MORITZ WallMountedThermostat
MORITZ ShutterContact
MORITZ PushButton
Uniroll All Devices
FHT FHT80b
ESA ESA1000
ESA ESA2000

More can be added easily: take a look at the files in the directory lib/ and find your inspiration on https://svn.fhem.de/fhem/trunk/fhem/FHEM/

Pull requests welcome!

further reading

Todo

  • configurable serialport auto reconnect
  • more data parser modules
    • MORITZ (MAX!) (inprogress)
    • ESA
    • HMS: HMS100WD, RM100-2, HMS100TFK, HMS100MG, HMS100CO, HMS100FIT
    • ...
  • more command modules
    • MORITZ (inprogress)
    • ...
  • more tests

Pull requests welcome! 😄

Credits

License

Licensed under GPLv2

Copyright (c) 2014-2020 Sebastian Raff [email protected] and Contributors

cul's People

Contributors

1stsetup avatar apollon77 avatar ferdinandhelmer avatar germanbluefox avatar hobbyquaker avatar klaernie avatar mreschka avatar ns130291 avatar timroemisch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

cul's Issues

Bring back node 4.x support by using scrict mode

Hi,

with 0.5.0 you removed nodejs 4.x support. For ioBroker I had the idea to update to 0.5 of the lib for the ioBroker.cul adapter, but loosing nodejs 4 is hard.

You can bring back nodejs 4 support by simply using sctrict mode (add "'use strict';" to all fixes on top). Then you get back nodejs 4: https://travis-ci.org/Apollon77/cul/builds/332285922

But I needed to remove the "xo" checks because it seems that they get "harder" when files are in strict mode (e.g. https://travis-ci.org/Apollon77/cul/jobs/332284580) ... wanted to clarify it first before bringing in an PR :-)

What do you think?

Add support for Node.js > 14?

Can we somehow get compatibility with node.js 16 or 18?
I use node-red-contrib-cul and when starting node-red everything looks fine, but commands are actually not sent to the device.

problem with installing on debian jessie / RPi2

when installing cul dependency the serialport lib will be translated. I get compile errors with serialport module 1.4.10:

`> [email protected] install /usr/local/lib/node_modules/serialport
> node-pre-gyp install --fallback-to-build

make: Entering directory '/usr/local/lib/node_modules/serialport/build'
  CXX(target) Release/obj.target/serialport/src/serialport.o
In file included from ../src/serialport.h:5:0,
                 from ../src/serialport.cpp:3:
../node_modules/nan/nan.h:261:25: error: redefinition of ‘template<class T> v8::Local<T> _NanEnsureLocal(v8::Local<T>)’
 NAN_INLINE v8::Local<T> _NanEnsureLocal(v8::Local<T> val) {
                         ^
../node_modules/nan/nan.h:256:25: note: ‘template<class T> v8::Local<T> _NanEnsureLocal(v8::Handle<T>)’ previously declared here
 NAN_INLINE v8::Local<T> _NanEnsureLocal(v8::Handle<T> val) {
                         ^
../node_modules/nan/nan.h:661:13: error: ‘node::smalloc’ has not been declared
     , node::smalloc::FreeCallback callback
             ^
../node_modules/nan/nan.h:661:35: error: expected ‘,’ or ‘...’ before ‘callback’
     , node::smalloc::FreeCallback callback
                                   ^
../node_modules/nan/nan.h: In function ‘v8::Local<v8::Object> NanNewBufferHandle(char*, size_t, int)’:
../node_modules/nan/nan.h:665:50: error: ‘callback’ was not declared in this scope
         v8::Isolate::GetCurrent(), data, length, callback, hint);
                                                  ^
../node_modules/nan/nan.h:665:60: error: ‘hint’ was not declared in this scope
         v8::Isolate::GetCurrent(), data, length, callback, hint);
                                                            ^
../node_modules/nan/nan.h: In function ‘v8::Local<v8::Object> NanNewBufferHandle(const char*, uint32_t)’:
../node_modules/nan/nan.h:672:67: error: call of overloaded ‘New(v8::Isolate*, const char*&, uint32_t&)’ is ambiguous
     return node::Buffer::New(v8::Isolate::GetCurrent(), data, size);
                                                                   ^
../node_modules/nan/nan.h:672:67: note: candidates are:
In file included from ../node_modules/nan/nan.h:25:0,
                 from ../src/serialport.h:5,
                 from ../src/serialport.cpp:3:
/root/.node-gyp/4.2.1/include/node/node_buffer.h:31:40: note: v8::MaybeLocal<v8::Object> node::Buffer::New(v8::Isolate*, v8::Local<v8::String>, node::encoding) <near match>
 NODE_EXTERN v8::MaybeLocal<v8::Object> New(v8::Isolate* isolate,
                                        ^
/root/.node-gyp/4.2.1/include/node/node_buffer.h:31:40: note:   no known conversion for argument 3 from ‘uint32_t {aka unsigned int}’ to ‘node::encoding’
/root/.node-gyp/4.2.1/include/node/node_buffer.h:43:40: note: v8::MaybeLocal<v8::Object> node::Buffer::New(v8::Isolate*, char*, size_t) <near match>
 NODE_EXTERN v8::MaybeLocal<v8::Object> New(v8::Isolate* isolate,
                                        ^
/root/.node-gyp/4.2.1/include/node/node_buffer.h:43:40: note:   no known conversion for argument 2 from ‘const char*’ to ‘char*’
In file included from ../src/serialport.h:5:0,
                 from ../src/serialport.cpp:3:
../node_modules/nan/nan.h: In function ‘v8::Local<v8::Object> NanNewBufferHandle(uint32_t)’:
../node_modules/nan/nan.h:676:61: error: could not convert ‘node::Buffer::New(v8::Isolate::GetCurrent(), size)’ from ‘v8::MaybeLocal<v8::Object>’ to ‘v8::Local<v8::Object>’
     return node::Buffer::New(v8::Isolate::GetCurrent(), size);
                                                             ^
../node_modules/nan/nan.h: In function ‘v8::Local<v8::Object> NanBufferUse(char*, uint32_t)’:
../node_modules/nan/nan.h:683:12: error: ‘Use’ is not a member of ‘node::Buffer’
     return node::Buffer::Use(v8::Isolate::GetCurrent(), data, size);
            ^
serialport.target.mk:90: recipe for target 'Release/obj.target/serialport/src/serialport.o' failed
make: *** [Release/obj.target/serialport/src/serialport.o] Error 1
make: Leaving directory '/usr/local/lib/node_modules/serialport/build'
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:270:23)
gyp ERR! stack     at emitTwo (events.js:87:13)
gyp ERR! stack     at ChildProcess.emit (events.js:172:7)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:200:12)
gyp ERR! System Linux 3.18.0-trunk-rpi2
gyp ERR! command "/usr/local/bin/node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "build" "--fallback-to-build" "--module=/usr/local/lib/node_modules/serialport/build/serialport/v1.7.4/Release/node-v46-linux-arm/serialport.node" "--module_name=serialport" "--module_path=/usr/local/lib/node_modules/serialport/build/serialport/v1.7.4/Release/node-v46-linux-arm"
gyp ERR! cwd /usr/local/lib/node_modules/serialport
gyp ERR! node -v v4.2.1
gyp ERR! node-gyp -v v3.0.3
gyp ERR! not ok
node-pre-gyp ERR! build error
node-pre-gyp ERR! stack Error: Failed to execute '/usr/local/bin/node /usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js build --fallback-to-build --module=/usr/local/lib/node_modules/serialport/build/serialport/v1.7.4/Release/node-v46-linux-arm/serialport.node --module_name=serialport --module_path=/usr/local/lib/node_modules/serialport/build/serialport/v1.7.4/Release/node-v46-linux-arm' (1)
node-pre-gyp ERR! stack     at ChildProcess.<anonymous> (/usr/local/lib/node_modules/serialport/node_modules/node-pre-gyp/lib/util/compile.js:83:29)
node-pre-gyp ERR! stack     at emitTwo (events.js:87:13)
node-pre-gyp ERR! stack     at ChildProcess.emit (events.js:172:7)
node-pre-gyp ERR! stack     at maybeClose (internal/child_process.js:818:16)
node-pre-gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5)
node-pre-gyp ERR! System Linux 3.18.0-trunk-rpi2
node-pre-gyp ERR! command "/usr/local/bin/node" "/usr/local/lib/node_modules/serialport/node_modules/.bin/node-pre-gyp" "install" "--fallback-to-build"
node-pre-gyp ERR! cwd /usr/local/lib/node_modules/serialport
node-pre-gyp ERR! node -v v4.2.1
node-pre-gyp ERR! node-pre-gyp -v v0.6.7
node-pre-gyp ERR! not ok
Failed to execute '/usr/local/bin/node /usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js build --fallback-to-build --module=/usr/local/lib/node_modules/serialport/build/serialport/v1.7.4/Release/node-v46-linux-arm/serialport.node --module_name=serialport --module_path=/usr/local/lib/node_modules/serialport/build/serialport/v1.7.4/Release/node-v46-linux-arm' (1)
npm ERR! Linux 3.18.0-trunk-rpi2
npm ERR! argv "/usr/local/bin/node" "/usr/local/bin/npm" "install" "-g" "--unsafe-perm" "[email protected]"
npm ERR! node v4.2.1
npm ERR! npm  v2.14.7
npm ERR! code ELIFECYCLE

npm ERR! [email protected] install: `node-pre-gyp install --fallback-to-build`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] install script 'node-pre-gyp install --fallback-to-build'.
npm ERR! This is most likely a problem with the serialport package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     node-pre-gyp install --fallback-to-build
npm ERR! You can get their info via:
npm ERR!     npm owner ls serialport
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /root/npm-debug.log
`

More complete testing thoughts ...

Hey Sebastian,

I have checked a bit. "Complete" testing for CUL-Net is kind of easy. Setup Net-Server and communication can be handled from both sides.

For serial it is more interesting:
One option is to use the Mock-Features from Serialport ... but as I tested for this we need access to the serialport instance of the cul instance ... because of strict mode and such it is not accessible directly, it would be needed to add some kind of "getSerialport" method ... for testing only ... not great :-(
But only alternative I found would be some kind of virtual serialports using socat or something like this. But this would be needed to be installed and started anytime tests are executed. Not very comfortable

What do you think about the options ?! ;-)

stackable_cc support in cul

I would love to find support for stacked CUL's/CUNO's here.
I have here for example a MAX!cube with a-culfw (CUBEx4_BL.bin) and 2 additional transmitters that communicates over lan with just one port (stacked).
In general it would just demand to add "*" to the raw command and detect and remove them from the reply.

No response from CULv3

I used the sample code from the readme and adapted it a bit, but I don't get an answer and the ready event isn't fired.

var Cul = require('cul');
var cul = new Cul({
    serialport: '/dev/ttyACM0',
    mode: 'AskSin'
});

cul.on('close', function () {
    console.log('serial connection closed');
});

cul.on('ready', function () {
    console.log('ready');
    cul.write('V');
});

cul.on('data', function (raw) {
    console.log(raw);
});

console.log('all events registered');

It only outputs all events registered.

node version: v0.10.29

Error with Max! Devices over CUNO device

Hi,
I have a strange error with the CUL Adapter with a flashed MAX! Cube as CUNO.
My window switches are found correctly but if I want to pair a MAX Radiator Thermostat basic, I got an error and the MAX Cube restarts.

Error:
MAX! Radiator Thermostat basic

cul.0 2018-07-16 20:36:54.377 error }
cul.0 2018-07-16 20:36:54.377 error }
cul.0 2018-07-16 20:36:54.377 error }
cul.0 2018-07-16 20:36:54.377 error return prop;
cul.0 2018-07-16 20:36:54.377 error if (this[prop] === value)
cul.0 2018-07-16 20:36:54.377 error if (this.hasOwnProperty(prop)) {
cul.0 2018-07-16 20:36:54.377 error for (var prop in this) {
cul.0 2018-07-16 20:36:54.377 error at TCP.onread (net.js:559:20) getKeyByValue=function (value) {
cul.0 2018-07-16 20:36:54.377 error at Socket.Readable.push (_stream_readable.js:134:10)
cul.0 2018-07-16 20:36:54.377 error at readableAddChunk (_stream_readable.js:176:18)
cul.0 2018-07-16 20:36:54.377 error at Socket.emit (events.js:188:7)
cul.0 2018-07-16 20:36:54.377 error at emitOne (events.js:96:13)
cul.0 2018-07-16 20:36:54.377 error at Socket.telnet.on.data (/opt/iobroker/node_modules/iobroker.cul/node_modules/cul/cul.js:218:17)
cul.0 2018-07-16 20:36:54.377 error at parse (/opt/iobroker/node_modules/iobroker.cul/node_modules/cul/cul.js:297:43)
cul.0 2018-07-16 20:36:54.377 error at Object.module.exports.parse (/opt/iobroker/node_modules/iobroker.cul/node_modules/cul/lib/moritz.js:183:50)
cul.0 2018-07-16 20:36:54.377 error TypeError: Cannot read property 'type' of undefined
cul.0 2018-07-16 20:36:54.377 error }
cul.0 2018-07-16 20:36:54.377 error }
cul.0 2018-07-16 20:36:54.377 error }

And every few seconds this appears in the LOG:

cul.0 2018-07-16 20:36:41.034 info }
cul.0 2018-07-16 20:36:41.034 info }
cul.0 2018-07-16 20:36:41.034 info }
cul.0 2018-07-16 20:36:41.034 info return prop;
cul.0 2018-07-16 20:36:41.034 info if (this[prop] === value)
cul.0 2018-07-16 20:36:41.034 info if (this.hasOwnProperty(prop)) {
cul.0 2018-07-16 20:36:41.034 info for (var prop in this) {
cul.0 2018-07-16 20:36:41.034 info -> getKeyByValue=function (value) {
cul.0 2018-07-16 20:36:41.034 info }
cul.0 2018-07-16 20:36:41.034 info }
cul.0 2018-07-16 20:36:41.034 info }

node-red wrapper

Great work!
I'm currently using FHEM as gateway from EIB/KNX to InterTechno (via CUL433) and from EnOcean (via EUL), however I plan to switch to Node-Red as logic engine (and as result also as gateway replacement). Do you plan to also provide a node-red wrapper for cul.js?

Max wallthermostat associate

Hi

Is there an option to associate a wall mounted thermostat with a heatint thermostat like in fhem ?

thx
regards
Chris

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.