BAC0
BAC0 copied to clipboard
Code after the bac0 code is not executed
Hello,
I am using BAC0 together with paho MQTT, but for my code, from where the BAC0 code is positioning, it seems that any code after the bac0 code is not executed.
for example:
bacnet = BAC0.connect(ip='192.xxx.xxx.xxx/24') bac0_measurement = bacnet.read('192.xxx.xxx.xxx analogInput 0 presentValue') for attr in device.attributes: payload = json.dumps({attr.name: random.randint(0,9)}}) logger.info("Send data to platform:" + payload) mqtt_client.publish( topic=f"/json/{service_group.apikey}/{device.device_id}/attrs", payload=json.dumps({attr.object_id: random.randint(0,9)})) time.sleep(1) entity = client.cb.get_entity(entity_id=device.device_id, entity_type=device.entity_type) logger.info("This is updated entity status after measurements are " "received: \n" + entity.json(indent=2))
Then all the code after BAC0.connect does not show anymore.
Is there a 'blocking' function from BAC0?
try this....don't do a BAC0.connect
but instead do a BAC0.lite()
app and make reads, writes, releases, or what not to the BAC0.lite app directly.
I played around with mqtt a little bit and BAC0 but did not put a lot of effort into this it was just to learn mqtt in an effort... I cobbled asnycio_mqtt and BAC0 together it worked to get BACnet data present value reads of sensor values on a temporary cloud server I was experimenting with.
I could rewrite this probably way better at this point in time....but this is the mqtt app: https://github.com/bbartling/bacnet-mqtt-publisher/blob/develop/old/mqtt_publisher.py
And from bacnet_actions import BacNetWorker
which should be eliminated and rewritten better:
https://github.com/bbartling/bacnet-mqtt-publisher/blob/develop/old/bacnet_actions.py
I'd be interested in resurrecting and making better....what is your end goal? Just to get data onto the cloud from the building? Or are you just interacting on the building level only with other MQTT systems?
It would be really cool to make a BAC0 MQTT gateway that is compliant by Google's Universal Device Management Interface (UDMI) schema:
- https://github.com/faucetsdn/udmi
- https://github.com/faucetsdn/udmi/tree/master/docs/learning
I can squash some code to together where this works for me to publish a sensor reading to an mqtt topic:
import BAC0, time, random
import random
import time
from paho.mqtt import client as mqtt_client
bacnet = BAC0.lite()
def bens_furnace_temp():
# test bench sensor
read_vals = f'12345:2 analogInput 2 presentValue'
sensor_reading = bacnet.read(read_vals)
return round(sensor_reading,3)
print(bens_furnace_temp())
broker = 'test.mosquitto.org'
port = 1883
# generate client ID with pub prefix randomly
client_id = "test_1"
topic_to_publish = f"bens/house/furnace/temperature"
topic_to_listen = f"mobile/publish"
topic_to_wildcard = f"testing/*"
username = ""
password = ""
def connect_mqtt():
def on_connect(client, userdata, flags, rc):
if rc == 0:
client.subscribe(topic_to_listen)
print(f"Connected to MQTT Broker on topic: {topic_to_wildcard}")
else:
print("Failed to connect, return code %d\n", rc)
client = mqtt_client.Client(client_id)
client.username_pw_set(username, password)
client.on_connect = on_connect
client.connect(broker, port)
client.on_connect = on_connect # Define callback function for successful connection
client.on_message = on_message # Define callback function for receipt of a message
return client
def publish(client):
while True:
msg = f"Sensor reading: {bens_furnace_temp()}"
result = client.publish(topic_to_publish, msg)
# result: [0, 1]
status = result[0]
if status == 0:
print(f"Send {msg} to topic {topic_to_publish}")
else:
print(f"Failed to send message to topic {topic_to_publish}")
time.sleep(20)
def on_message(client, userdata, msg): # The callback for when a PUBLISH message is received from the server.
print("Message received-> " + msg.topic + " " + str(msg.payload))
def run():
client = connect_mqtt()
client.loop_start()
publish(client)
if __name__ == '__main__':
run()
Looks like this:
Send Sensor reading: 74.98 to topic bens/house/furnace/temperature
Send Sensor reading: 74.98 to topic bens/house/furnace/temperature
Send Sensor reading: 74.98 to topic bens/house/furnace/temperature
Send Sensor reading: 74.98 to topic bens/house/furnace/temperature
Send Sensor reading: 74.96 to topic bens/house/furnace/temperature
try this....don't do a
BAC0.connect
but instead do aBAC0.lite()
app and make reads, writes, releases, or what not to the BAC0.lite app directly.I played around with mqtt a little bit and BAC0 but did not put a lot of effort into this it was just to learn mqtt in an effort... I cobbled asnycio_mqtt and BAC0 together it worked to get BACnet data present value reads of sensor values on a temporary cloud server I was experimenting with.
I could rewrite this probably way better at this point in time....but this is the mqtt app: https://github.com/bbartling/bacnet-mqtt-publisher/blob/develop/old/mqtt_publisher.py
And
from bacnet_actions import BacNetWorker
which should be eliminated and rewritten better: https://github.com/bbartling/bacnet-mqtt-publisher/blob/develop/old/bacnet_actions.pyI'd be interested in resurrecting and making better....what is your end goal? Just to get data onto the cloud from the building? Or are you just interacting on the building level only with other MQTT systems?
Thank you very much for your reply and the advices.
My goal is to get data onto the cloud from the building
For what its worth I was curious to build off these concepts on issue #346 where I almost think it would be better practice (?) using a data base to go in between MQTT scripts and BAC0 for BACnet....So maybe there is better thread of communication to keep this idea alive.
@ChristianTremblay does this git repo have a "discussions" feature?
@Ferkelcode, here's an example with the connect()
instead of lite()
way of scraping BACnet data....where I said early to use lite()
instead of connect
I think I take that back like we should use connect
instead...hopefully @ChristianTremblay can put his blessing on this as well. For example using connect
incorporates BACnet polling instead of BACnet read requests that is used on the lite()
method...? And Polling is better/healthier for the BACnet network right? Like we always want to cut down/minimalize read
requests on networks when we can, right?
Also sort of curious on the connect
method we can connect to multiple devices, right? I only know how to connect to one, is there code snip examples to connect to multiple?
@ChristianTremblay does the time.sleep
in the def publish(client):
will that pause BAC0 BACnet operations too on polling the BACnet network and gathering data into Pandas?
import BAC0, time, random
import random
import time
from paho.mqtt import client as mqtt_client
bacnet = BAC0.lite()
obj_list = [('file', 1),
('analogInput', 2),
('analogInput', 3)]
my_device = BAC0.device('12345:2',
201201,
bacnet,
object_list=obj_list,
segmentation_supported=False)
broker = 'test.mosquitto.org'
port = 1883
# generate client ID with pub prefix randomly
client_id = "test_1"
topic_to_publish = f"bens/house/furnace/temperature"
topic_to_listen = f"mobile/publish"
topic_to_wildcard = f"testing/*"
username = ""
password = ""
def connect_mqtt():
def on_connect(client, userdata, flags, rc):
if rc == 0:
client.subscribe(topic_to_listen)
print(f"Connected to MQTT Broker on topic: {topic_to_wildcard}")
else:
print("Failed to connect, return code %d\n", rc)
client = mqtt_client.Client(client_id)
client.username_pw_set(username, password)
client.on_connect = on_connect
client.connect(broker, port)
client.on_connect = on_connect # Define callback function for successful connection
client.on_message = on_message # Define callback function for receipt of a message
return client
def publish(client):
while True:
for point in my_device.points:
data = {
point.properties.name: point.value
}
print(data)
msg = f"Sensor reading is {point.properties.name}: {round(point.value,2)}"
result = client.publish(topic_to_publish, msg)
# result: [0, 1]
status = result[0]
if status == 0:
print(f"Send {msg} to topic {topic_to_publish}")
else:
print(f"Failed to send message to topic {topic_to_publish}")
time.sleep(60)
def on_message(client, userdata, msg): # The callback for when a PUBLISH message is received from the server.
print("Message received-> " + msg.topic + " " + str(msg.payload))
def run():
client = connect_mqtt()
client.loop_start()
publish(client)
if __name__ == '__main__':
run()
Hello,
I am using BAC0 together with paho MQTT, but for my code, from where the BAC0 code is positioning, it seems that any code after the bac0 code is not executed.
for example:
bacnet = BAC0.connect(ip='192.xxx.xxx.xxx/24') bac0_measurement = bacnet.read('192.xxx.xxx.xxx analogInput 0 presentValue') for attr in device.attributes: payload = json.dumps({attr.name: random.randint(0,9)}}) logger.info("Send data to platform:" + payload) mqtt_client.publish( topic=f"/json/{service_group.apikey}/{device.device_id}/attrs", payload=json.dumps({attr.object_id: random.randint(0,9)})) time.sleep(1) entity = client.cb.get_entity(entity_id=device.device_id, entity_type=device.entity_type) logger.info("This is updated entity status after measurements are " "received: \n" + entity.json(indent=2))
Then all the code after BAC0.connect does not show anymore.
Is there a 'blocking' function from BAC0?
BAC0 is based on bacpypes which is synchronous. Every network messages are piled up in a stack and are sent one after the other.
BAC0 is built based on threads that are allowing some parallelism. Like defining devices (BAC0.devices
) will create the device with everything in it and start a polling task that will read points at a specified rate. Each read will be stores in a pandas series (device['point'].history
) that can be used later.
So instead of relying on manual read, you can define a device....let the polling do its job.... and use
device['point'].lastValue
and use this in your code. This will not create supplemental reading on the network. If for some reason you need the value to be fresh... device['point'].value
will force a read.
Last value is just taking the last value from history pandas series.
@bbartling
Would something like this work ?
import BAC0, time
import random
import time
from paho.mqtt import client as mqtt_client
from BAC0.tasks.RecurringTask import RecurringTask
bacnet = BAC0.lite()
# you won't use file... so don't bother with it.
obj_list = [("analogInput", 2), ("analogInput", 3)]
# poll=60 will read all the point every 60 seconds....default is 10sec...and it's too fast often
my_device = BAC0.device(
"12345:2",
201201,
bacnet,
object_list=obj_list,
segmentation_supported=False,
poll=60,
)
broker = "test.mosquitto.org"
port = 1883
# generate client ID with pub prefix randomly
client_id = "test_1"
topic_to_publish = f"bens/house/furnace/temperature"
topic_to_listen = f"mobile/publish"
topic_to_wildcard = f"testing/*"
username = ""
password = ""
def connect_mqtt():
def on_connect(client, userdata, flags, rc):
if rc == 0:
client.subscribe(topic_to_listen)
print(f"Connected to MQTT Broker on topic: {topic_to_wildcard}")
else:
print("Failed to connect, return code %d\n", rc)
client = mqtt_client.Client(client_id)
client.username_pw_set(username, password)
client.on_connect = on_connect
client.connect(broker, port)
client.on_connect = on_connect # Define callback function for successful connection
client.on_message = on_message # Define callback function for receipt of a message
return client
def publish(client):
for point in my_device.points:
msg = f"Sensor reading is {point.properties.name}: {round(point.lastValue,2)}"
try:
result = client.publish(topic_to_publish, msg)
# result: [0, 1]
status = result[0]
if not status == 0:
raise SendingFailed(
f"Failed to send message to topic {topic_to_publish}"
)
except SendingFailed() as e:
print(e)
print(
msg
) # could probably be removed... on_message callback should do the job no ?
def on_message(
client, userdata, msg
): # The callback for when a PUBLISH message is received from the server.
print("Message received-> " + msg.topic + " " + str(msg.payload))
def run():
client = connect_mqtt()
client.loop_start()
update_task = RecurringTask(
(
publish,
[
client,
],
),
delay=10,
)
update_task.start()
while True:
time.sleep(0.01)
if __name__ == "__main__":
run()
class SendingFailed(Exception):
pass
@Ferkelcode Here is a general canvas... won't work right out but I'm pretty sure you can make it from there
import BAC0
from BAC0.tasks.RecurringTask import RecurringTask
import json
import random
import logging
import time
logger = logging.getLogger()
# if you don'T need a web server, use lite
# ip here is the IP of your network interface
bacnet = BAC0.lite(ip='192.xxx.xxx.xxx/24')
# This will read the value only 1 time...
# bac0_measurement = bacnet.read('192.xxx.xxx.xxx analogInput 0 presentValue')
# replace by a device to poll points on a regular basis using BAC0.device (here every 60 sec)
device = BAC0.device('ip_of_device', 'device_id_integer', bacnet, poll=60)
# No device created ?
def pub(mqtt_client):
for point in device.points:
obj_id = f"{device.properties.type}:{device.properties.address}"
payload = json.dumps({point.properties.name: random.randint(0,9)}})
logger.info("Send data to platform:" + payload)
mqtt_client.publish(
topic=f"/json/{service_group.apikey}/{device.properties.device_id}/attrs",
payload=json.dumps({obj_id: random.randint(0,9)}))
logger.info("This is updated entity status after measurements are "
"received: \n" + entity.json(indent=2))
client = "SomeClientForMQTT"
entity = client.cb.get_entity(entity_id=device.device_id,
entity_type=device.entity_type)
publish_task = RecurringTask((pub,[client,]), delay=10)
publish_task.start()
while True:
time.sleep(0.01)