Giter Club home page Giter Club logo

bacure's Introduction

Bacure

A clojure library wrapping the excellent BACnet4J library. Hopefully it will be able to abstract some of the ugly BACnet details (datatypes) and provide a seamless Clojure experience.

Table of Contents

Usage

Add the following dependency in your project.clj:

Clojars Project

Check the documentation for the available functions with their descriptions.

Getting Started

To spin up a BACnet device, you can use bacure.core/boot-up!. This will create a new local device, bind it to a network interface and search for other BACnet devices.

IPv4

The default boot-up! behavior uses IPv4. If you need to specify an interface (for example if you have an Ethernet port AND a Wifi on your computer), use the broadcast address associated with the interface.

(bacure.core/boot-up! {:broadcast-address "192.168.1.255"
                       :device-id 3333
                       :object-name "My awesome BACnet device"})

MSTP

For MSTP, we will typically want to be a Master node, and this is the default. Here's an example of how to do this on Linux:

(bacure.core/boot-up! {:network-type :mstp
                       :device-id    3333
                       :object-name  "My awesome BACnet device"
                       :com-port     "ttyS1"
                       :baud-rate    9600
                       :mstp-config  {:local-node-id      6
                                      :max-master-address 6}})

See MSTP Configuration for more details.

Configuration Details

The optional config map can contain the following:

Keyword Type Default Description
:network-type :ipv4 or :mstp :ipv4 Specifies which type of network to create. Other config keywords may or may not be needed based on this value.
:device-id number 1338 The device identifier on the network. It should be unique.
:other-configs anything nil Any configuration returned when using the function 'get-configs'. These configuation can be set when the device is created simply by providing them in the arguments. For example, to change the vendor name, simply add '{:vendor-name "some vendor name"}'.
:model-name string "Bacure"
:object-name string "Bacure "
:vendor-identifier number 697
:apdu-timeout number 6000 Time in milliseconds
:number-of-apdu-retries number 2
:description string see local_device.clj
:vendor-name string "HVAC.IO"
:foreign-device-target {:host string :port number} nil Will try to register as a foreign device to the provided host.

IPv4 Configuraion

The following optional keys are for IPv4 (:network-type = :ipv4)

Keyword Type Default Description
:broadcast-address string (generated) The address on which we send 'WhoIs'. You should not have to provide anything for this, unless you have multiple interfaces or want to trick your machine into sending to a 'fake' broadcast address.
:port string 47808 The BACnet port, usually 47808.
:local-address string 0.0.0.0 The default, "0.0.0.0", is also known as the 'anylocal'. (Default by the underlying BACnet4J library.) This is required on Linux, Solaris and some Windows machines in order to catch packet sent as a broadcast. You can manually change it, but unless you know exactly what you are doing, bad things will happen.

MSTP Configuration

The following keys are for MSTP (:network-type = :mstp)

Keyword Type Default Description
:com-port string (REQUIRED) On Linux, this is usually /dev/ttyS[0-9] or /dev/ttyUSB[0-9]. For Windows, it's COM[0-9]*. You can use (serial.util/list-ports) to see what you have. (On Linux, make sure you have appropriate permissions, or you'll get "port in use" errors. I usually just change the permissions to 666, using something like this
:baud-rate number 115200 Supported speeds are 1200, 2400, 4800, 9600, 19200, 38400, 57600 and 115200 bits per second.
:databits DATABITS_* DATABITS_8 These live in serial.core
:stopbits STOPBITS_* STOPBITS_1 These live in serial.core
:parity PARITY_* PARITY_NONE These live in serial.core
:mstp-config map nil Additional MSTP configuration. See below.

The following keys can be included in the :mstp-config map mentioned above:

Keyword Type Default Description
:node-type :mstp :master or :slave :master Only Master nodes can initiate requests and pass tokens. Slave nodes can only respond to requests, and are not part of the token-passing ring. More information
:node-id :mstp number 1 Must be unique on the network. (The MAC address must also be unique, by the way!)
:debug-traffic :mstp boolean false Turns on some very chatty logging in the REPL or console, which spits out all frames in and out. One of several debugging outlets, unfortunately.
:retry-count :mstp number 3 Relevant for Master nodes only. Specifies the number of transmission retries used for Token and Poll For Master transmissions.
:max-info-frames :mstp number 8 Specifies how many messages the controller can send out to other controllers when it has the token on the network.
:max-master-id :mstp number 127 Highest node-id to search when doing Poll-for-Master. It's optimal to have your node-ids close to each other, and to set this value to no higher than your highest node-id.

Multiple local devices

It is now possible to have more than a local device in memory, identified by their BACnet IDs. For example, one could have device 1338 with a broadcast address of 192.168.1.255 and device 1339 with a broadcast address of 172.180.255.255. Unless the device ID is given as an argument, most functions will act with the first local device they can find.

; the following returns the remote devices for the local device 1339
(bacure.remote-device/remote-devices 1339)

; => #{10100, 10200}

Data coercion

Higher level functions will automatically convert clojure datastructure to the correct bacnet4j java type, so you shouldn't have to worry about that. However, if for some reason you need to do the conversions manually, you can use the coercion functions as such :

(require '[bacure.coerce :as c])

;; convert from clojure to bacnet4j :

(c/clojure->bacnet :unsigned-integer 10)

; => #object[com.serotonin.bacnet4j.type.primitive.UnsignedInteger 0x5b2efe25 "10"]


;; convert from bacnet4j to clojure

(def aaa (c/clojure->bacnet :unsigned-integer 10)) ;; first we create a bacnet4j object


(c/bacnet->clojure aaa)

; => 10

If you don't know what kind of data is expected, you can use the example function :

(c/example :object-identifier)

; => [:analog-input 0]

Debugging Serial / MSTP

The MSTP network uses clj-serial, which uses PureJavaComm for serial communication.

Unfortunately, BACnet4J and PureJavaComm use different methods of logging. Here's a summary:

  • To see BACnet4J log messages, see log/bacnet4j.log. Bacure's default configuration uses the WARN level of detail, but this can be configured using bacure/src/log4j.properties. To see pretty much all of the traffic, set the log level to TRACE.
  • To see PureJavaComm's output dump, set purejavacomm.loglevel in the :jvm-opts in project.clj to something higher than 0 (and less than 7). This is also REPL/console output.

ProTip: Don't use Wireshark / mstpcap while running this on your PC. I thought the code was broken for the longest time until I realized that mstpcap was somehow interfering with the frames.

License

Copyright © 2019 Frozenlock

GNU General Public License version 3.0 (GPLv3)

bacure's People

Contributors

frozenlock avatar whittlesjr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

bacure's Issues

Dependency resolution error

As of 1.1.X, I seemingly can't use bacure as a dependency:

Error building classpath. Unable to resolve lohbihler/sero-scheduler version: [1.0.0,2)

It does work on 1.0.8 though. Do you just need to roll back sero-scheduler to 1.0.0?

DeviceEventAdapter not triggering iAmReceived

I've tried multiple versions of bacure and I'm failing to get this to work recently, so it's probably an issue with my environment or config or something.

bacure.core/boot-up! and bacure.remote-device/discover-network aren't adding remote devices for me anymore. I see the IAm responses coming in Wireshark, but I tried dropping some debug prn statements in iAmReceived but they never trigger. I just end up with an empty set of remote devices. Anything coming to mind that I might be doing wrong?

> ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether f8:b1:56:d7:a4:e9 brd ff:ff:ff:ff:ff:ff
    inet 10.200.84.88/24 scope global eno1
       valid_lft forever preferred_lft forever
    inet6 fe80::fab1:56ff:fed7:a4e9/64 scope link 
       valid_lft forever preferred_lft forever
(bacure.core/boot-up! {:broadcast-address "10.200.84.255"})

bacure-capture.zip

IP device "dies" after a few minutes?

I feel like we've talked about this before, but I can't find the conversation.

My IP-based local device will just stop sending requests after a few minutes. For example, I'll run

(bacure.remote-device/find-remote-devices 100203 {:min-range nil, :max-range nil})

but I see nothing in Wireshark. My request never went out the door.

If I kill and re-create my local device, things start working happily again for a few minutes.

I can try to add more detail, but have you experienced anything like this, or is it just me?

Insecure HTTP repo

I don't think it's BACnet4J anymore, at least not if you use 4.1.5... I need to dig a bit more to see what it is.

We should also update to 4.1.5 to get the HTTPS fix.

But I also can't build bacure out-of-the-box without lein install-ing the HEAD of clj-serial (because it needs to cut a release.

But even with 4.1.5 and clj-serial's HEAD, I still get Insecure HTTP repo.

Fix MSTP to upgrade to 4.1.2

The MasterNode constructor is different in 4.1.2.

MasterNode(SerialPortWrapper wrapper, byte thisStation, int retryCount)
MasterNode(java.lang.String portId, java.io.InputStream in, java.io.OutputStream out, byte thisStation, int retryCount)

@WhittlesJr can you take a look?

Problem discovering the network

Compared to pre-v4 switch, Bacure no longer discovers the vast majority of the network (possibly the non-IP devices).

Need to find out where the problem appeared : switch to V4 or when we dropped the device discoverer?

Edit : tested with 6e189de. Same problem. It appears to be caused by the switch to V4.

Is the BACnet4J fork still needed?

In project.clj, you have this note:

;; we use a fork of bacnet4j until https://github.com/infiniteautomation/BACnet4J/issues/23 is fixed

It looks like that issue is fixed. Do you still need to source your dependency from this fork, or can you use an official BACnet4J release?

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.