This is a fork of Bacnet. This implementation includes an MQTT client sub-system that can used by the Bacnet Server to publish an MQTT message to an MQTT broker for the following conditions:
- A write/set operation is performed on the server's object properties.
- An new event is triggered or state changes.
Configure config on location: <g>/config/<s>
Start Command:
g=<path for global_directory> s=config.yml ./app
For example:
g=/data/bacnet-server-c s=config.yml ./app
on your pc
g=/home/user/code/bacnet s=config.yml ./app-amd64
The values of the following object properties can be updated via MQTT publish command:
- Object Name (name) - applies to analog input (ai), analog output (ao), analog value (av), binary input (bi), binary output (bo) and binary value (bv) objects
- Present Value (pv) - applies to analog input (ai), analog output (ao), analog value (av), binary input (bi), binary output (bo) and binary value (bv) objects
- Priority Array (pri) - applies to analog output (ao), analog value (av), binary output (bo) and binary value (bv) objects
The value of the publish message must be in JSON using the following format:
{"value" : "value here", "uuid" : "uuid here"}
Object Name topic format:
bacnet/object/address/write/name
Write "ao_name1" into analog object (ao) name at instance (address) 1
topic: bacnet/ao/1/write/name
json payload: {"value" : "ao_name1", "uuid" : "123456"}
Present Value topic format:
bacnet/object/address/write/pv
Write 10.50 to into analog object (ao) present value at instance (address) 1
topic: bacnet/ao/1/write/pv
json payload: {"value" : "10.50", "uuid" : "123456"}
Priority Array topic formats:
bacnet/object/address/write/pri/priority_index
bacnet/object/address/write/pri/priority_index/all
Write 50.20 into analog object (ao) at instance (address) 1 at priority index 10
topic: bacnet/ao/1/write/pri/10
json payload: {"value" : "10.50", "uuid" : "123456"}
Write 99.99 into analog object (ao) at instance (address) 1 to all priority slots
topic: bacnet/ao/1/write/pri/16/all
json payload: {"value" : "99.99", "uuid" : "123456"}
Reset priority slots #10 of analog object (ao) at instance (address) 1. Reset applies only to analog ouput, analog value, binary output and binary value objects.
topic: bacnet/ao/1/write/pri/10
json payload: {"value" : "null", "uuid" : "123456"}
Reset all priority slots of analog object (ao) at instance (address) 1
topic: bacnet/ao/1/write/pri/16/all
json payload: {"value" : "null", "uuid" : "123456"}
The MQTT C libary is the Eclipse Paho C Client Library for MQTT protocol. The source can be downloaded from https://github.com/eclipse/paho.mqtt.c. Please follow the install instructions to install the library.
In the server Makefile, change or include the following.
--
MQTT_SRC = mqtt_client.c
--
OBJS += ${SRC:.c=.o} ${MQTT_SRC:.c=.o}
MQTT_CFLAGS = -DMQTT -DMQTT_PUBLISH -I/usr/local/include -I${BACNET_SRC_DIR}/../apps/server
MQTT_LFLAGS = -L/usr/local/lib -lpaho-mqtt3c
--
${TARGET_BIN}: ${OBJS} Makefile ${BACNET_LIB_TARGET}
${CC} ${PFLAGS} ${OBJS} ${LFLAGS} ${MQTT_LFLAGS} -o $@
--
.c.o:
${CC} -c ${CFLAGS} ${MQTT_CFLAGS} $*.c -o $@
--
The source files are currently under the Bacnet server module (app/server). Include mqtt_client.h to use the MQTT client sub-system.
#if defined(MQTT)
#include "mqtt_client.h"
#endif /* defined(MQTT) */
To initialize the MQTT client sub-system, call mqtt_client_init().
#if defined(MQTT)
mqtt_client_init();
#endif /* defined(MQTT) */
To shutdown/clean-up the MQTT client sub-system, call mqtt_client_shutdown().
#if defined(MQTT)
mqtt_client_shutdown();
#endif /* defined(MQTT) */
To publish an MQTT message, call mqtt_publish_topic() with the pre-defined topic ID (see topic and object/property-name mapping section) and value (either a C-string or a Bacnet string).
#if defined(MQTT)
mqtt_publish_topic(DEVICE_OBJECT_NAME_TOPIC_ID,
MQTT_TOPIC_VALUE_BACNET_STRING, &value.type.Character_String);
#endif /* defined(MQTT) */
Topic and Object/Property-Name mappings are pre-defined. Each topic has an ID and defined in apps/server/mqtt_client.h.
#define DEVICE_OBJECT_NAME_TOPIC_ID 0
#define BINARY_OUTPUT_OBJECT_NAME_TOPIC_ID 1
#define TOPIC_ID_MAX 2
The textual names of the Object/Property-Name and their Topic ID mappings are defined in apps/server/mqtt_client.c.
/* topic and object/property mappings */
static topic_mapping_t topic_mappings[] = {
{ DEVICE_OBJECT_NAME_TOPIC_ID,
"device_object_name" },
{ BINARY_OUTPUT_OBJECT_NAME_TOPIC_ID,
"binary_output_object_name" },
{ TOPIC_ID_MAX, NULL }
};
New ones much be added before the mapping with the topic ID TOPIC_ID_MAX.
The format of the MQTT topic published to MQTT broker is /<device_id>/object-property-name. For example the topic of an MQTT publish message sent when updating the Bacnet device name of a Bacnet server with a device ID 1234 would be:
/1234/device_object_name
The topic for Bacnet Binary Output Propery Name would be:
/1234/binary_output_object_name
The default MQTT broker IP and port is 127.0.0.1 and 1883 respectively. To set the MQTT broker IP to a different IP, set the IP in the environment variable DEFAULT_MQTT_BROKER_IP. To set the MQTT broker port number to a different port, set the port in the environment variable MQTT_BROKER_PORT.
For example:
MQTT_BROKER_IP=10.20.30.123 MQTT_BROKER_PORT=11883 ./bin/bacserv
Compile and build the bacnet server on your local development machine. Tested on Ubuntu 18.04.5 LTS.
sudo apt install build-essential net-tools git libssl-dev cmake -y
mkdir bacnet && cd bacnet
git clone https://github.com/eclipse/paho.mqtt.c paho.mqtt.c
cd paho.mqtt.c && cmake -DPAHO_BUILD_STATIC=TRUE && sudo make install
cd .. && git clone https://github.com/json-c/json-c json-c
cd json-c && mkdir -p json-c-build && cmake ../json-c && make && sudo make install
sudo apt-get install libyaml-dev -y
cd .. && git clone https://github.com/tlsa/libcyaml.git
cd libcyaml && sudo make install VARIANT=release
find / -name libyaml.a -print -exec cp -fR {} /usr/lib \;
cd .. && git clone git@github.com:NubeIO/bacnet-server-c.git
cd bacnet-server-c/bacnet-stack && make clean all
The bacnet server binary file is at bacnet-stack/bin/bacserv. You need to specify the configuration file and folder to run the server using the "g" and "s" ENV variables like below.
g=/data/bacnet-server-driver s=config.yml ./bin/bacserv
Get and set the device propery name. The client and server are on the same machine here. If the client is on a different machine, you can omit the "mac" option.
Get the device object property name.
./bin/bacrp 1234 8 1234 77 --mac 10.104.0.11:47808
"SimpleServer"
To change the device object property name to "My Simple Server".
./bin/bacwp 1234 8 1234 77 0 -1 7 "My Simple Server" D 10.104.0.11:47808
WriteProperty Acknowledged!
Confirm the change was made.
./bin/bacrp 1234 8 1234 77 --mac 10.104.0.11:47808
"My Simple Server"
Get and set the binary output object propery name. Get the binary output object propery name.
./bin/bacrp 1234 4 1 77 --mac 10.104.0.11:47808
"BINARY OUTPUT"
To change the binary output object property name to "MY BINARY OUTPUT".
./bin/bacwp 1234 4 1 77 0 -1 7 "MY BINARY OUTPUT" D 10.104.0.11:47808
WriteProperty Acknowledged!
Confirm the change was made.
./bin/bacrp 1234 4 1 77 --mac 10.104.0.11:47808
"MY BINARY OUTPUT"
You can use any MQTT protocol compliant client. I used the mqtt-cli. To subscribe to changes to the device object and binary output object property name of the bacnet instance with device ID 1234.
mqtt sub -h <mqtt broker ip address> -t "/1234/binary_output_object_name" -t "/1234/device_object_name" -T
The client will receive a publish message when a change is made to the device object and binary output object propery name with the new value in the message.
mqtt sub -h <mqtt broker ip address> -t "/1234/binary_output_object_name" -t "/1234/device_object_name" -T
/1234/device_object_name: My Simple Server
/1234/binary_output_object_name: MY BINARY OUTPUT