BAC0

BAC0 is a script module based on bacpypes (https://github.com/JoelBender/bacpypes.git) to automate task using Bacnet/IP protocole. It's mainly targetted as a tool to test sequences on DDC controlelrs using bacnet.

Using the simplciity of python, the power of pandas, it's easy to test and keep a trace of the history of each points.

How to use

First you must install the 2 modules pip install bacpypes

Note : All tests have been done in Windows 7 using Anaconda3 (http://continuum.io/downloads)

Import module


In [1]:
import BAC0
import pandas as pd
%matplotlib inline
# Define network and connect to it
bacnet = BAC0.connect()


/home/pi/miniconda3/lib/python3.4/importlib/_bootstrap.py:321: FutureWarning: The pandas.lib module is deprecated and will be removed in a future version. These are private functions and can be accessed from pandas._libs.lib instead
  return f(*args, **kwds)
xlwings not installed. If using Windows or OSX, install to get more features.
Using ip : 192.168.111.13
Click here to open Live Trending Web Page
http://localhost:5006/?bokeh-session-id=WMT6jGoglqAs2Sw2fhmwJhuZF6MsObrLDakK7d7N5kbo

In [2]:
BAC0.version


Out[2]:
'0.99.100'

In [2]:
# Define the controller using : controller = BAC0.device(address, device_id, network)
fx = BAC0.device('2:5',5,bacnet)


Found FX14 0005... building points list
Ready!
Polling started, every values read each 10 seconds

In [4]:
# Access points list
fx.points


Out[4]:
[nvoAI3 : 3.74 degreesCelsius,
 nvoAI4 : 45.65 percent,
 nvoAI6 : 345.20 kilopascals,
 nvoAI5 : 1.85 percent,
 nvoAI1 : 44.87 degreesCelsius,
 nvoAI2 : 22.76 degreesCelsius,
 nvoDO6 : 13.85 percent,
 nvoEffTempEtage : 22.87 degreesCelsius,
 nvoEffTempSS : 20.77 degreesCelsius,
 nvoTempRdC : 21.83 degreesCelsius,
 nciPCTExtMinVolet : -12.00 degreesCelsius,
 nciPIDBLTRetPC : 20.00 degreesCelsius,
 nvoDemChauff : 98.66 percent,
 nvoDemRefroid : 0.00 percent,
 nvoEffPCSS : 22.00 degreesCelsius,
 nvoPCCTAli : 44.68 degreesCelsius,
 nvoEffPCEtage : 22.20 degreesCelsius,
 nciPIDTPSousSolPB : 5.00 degreesCelsius,
 nciPIDTPSousSolTI : 800.00 seconds,
 nciPIDTPEtageTI : 800.00 seconds,
 nciPIDTPRdCTI : 800.00 seconds,
 nciPIDTPEtagePB : 5.00 degreesCelsius,
 nciPIDTAliPB : 10.00 degreesCelsius,
 nciPIDTAliTI : 90.00 seconds,
 nciPCTAliMax : 45.00 degreesCelsius,
 nciPCTAliMin : 13.00 degreesCelsius,
 nciPCTAliMed : 22.00 degreesCelsius,
 nciPIDHumPB : 30.00 percent,
 nciPIDHumTI : 120.00 seconds,
 nciPIDDeshumTI : 120.00 seconds,
 nvoPIDDeshumOut : 0.00 percent,
 nciPIDDeshumPB : 30.00 percent,
 nvoPIDHumOut : 0.00 percent,
 nciDemRefroidHV : 95.00 percent,
 ncikWTotal : 15.00 noUnits,
 nciDeshumNivHV : 50.00 percent,
 nciPIDHumPC : 30.00 percent,
 nvoEffectkW : 0.66 noUnits,
 nvoPressionEauPSI : 50.07 noUnits,
 nvoPIDTPSousSolOut : 50.00 percent,
 nvoPIDTPRdCOut : 0.69 percent,
 nvoPIDTPEtageSortie : 50.00 percent,
 nciDemChauffHV : 90.00 percent,
 nciDelaiMinOnHV : 120.00 seconds,
 nciDiffAlrmPmp : 0.00 kilopascals,
 nciPCBassePression : 0.00 kilopascals,
 nciDelaiAlrmPompe : 120.00 seconds,
 nviPCEtage : 22.20 degreesCelsius,
 nviTempEtage : 22.87 degreesCelsius,
 nviPCSousSol : 22.00 degreesCelsius,
 nviTempSousSol : 20.78 degreesCelsius,
 nciPIDBLTRetPB : 5.00 degreesCelsius,
 nvoAO1 : 100.00 percent,
 nciPIDDeshumPC : 60.00 percent,
 nciPIDBLTRetTI : 60.00 seconds,
 nvoAO2 : 0.00 percent,
 nciDureeOccupSousSol : 180.00 minutes,
 nciDelaiMinModeUrgen : 60.00 minutes,
 nciPIDTPRdCPB : 5.00 degreesCelsius,
 nciPCTPRdCAbsent : 20.00 degreesCelsius,
 nciPCTRetMinUrgence : 15.00 degreesCelsius,
 nciPCTExtPrmChauffTP : 16.00 degreesCelsius,
 nciPCTExtPrmClim : 13.00 degreesCelsius,
 nciPCTExtPrmSCR : 10.00 degreesCelsius,
 nciPCTExtMinChauffTP : -12.00 degreesCelsius,
 nciResetPompe : OFF,
 nciOvrdDO9.State : AUTO,
 nciOvrdDO8.State : AUTO,
 nciOvrdDO6.State : AUTO,
 nciOvrdDO7.State : AUTO,
 nvoEtapeAct : Chauffage,
 SCH_nvoHoraire.Curre : Occupied,
 nviOccupRequestSousS : ERR,
 nviOccupRequestEtage : ERR,
 nvoProbSondeSS : OK,
 nvoProbSondeEtage : Ok,
 nciOvrdDO5.State : AUTO,
 nvoAlarmPompe : OFF,
 nvoAlrmGravePompe : OFF,
 nvoTempOccup : OFF,
 nvoEffOccupancy : Occupe,
 nciModeOperation : AUTO,
 nciSelectConsigne : Auto,
 nvoConsActuelle : RezDeChaussee,
 nciOvrdDO2.State : AUTO,
 nciOvrdDO3.State : AUTO,
 nciOvrdDO4.State : AUTO,
 nciOvrdDO1.State : AUTO,
 nciModeDeshum : Aucune,
 nciOvrdAO1.State : AUTO,
 nciOvrdAO2.State : AUTO,
 nvoDI7 : False,
 nvoDI8 : False,
 nvoDI10 : False,
 nvoDI9 : False,
 nvoDI6 : False,
 nvoDI4 : False,
 nvoDI3 : False,
 nvoDI5 : False,
 nvoDI1 : True,
 nvoDI2 : False,
 nvoDI11 : False,
 nvoDI12 : True,
 nvoDO8 : True,
 nvoDO7 : False,
 nvoDO3 : True,
 nvoDO9 : False,
 nvoDO2 : False,
 nvoDO1 : False,
 nvoDO5 : False,
 nvoDO4 : True,
 nciHumidif : False]

In [6]:
# Create a table with multiple points

lst = ['nvoAI1', 'nvoAI2', 'nvoDI1']

fx.df(lst).fillna(method='ffill')


Out[6]:
nvoAI1 nvoAI2 nvoDI1
2015-11-15 08:40:21.102146 44.950001 NaN NaN
2015-11-15 08:40:21.117771 44.950001 22.799999 NaN
2015-11-15 08:40:31.172206 44.950001 22.799999 active
2015-11-15 08:40:32.605017 44.869999 22.760000 active
2015-11-15 08:40:36.223253 44.869999 22.760000 active
2015-11-15 08:40:48.120203 44.740002 22.799999 active
2015-11-15 08:40:51.763943 44.740002 22.799999 active
2015-11-15 08:40:53.399209 44.740002 22.799999 active
2015-11-15 08:40:53.539834 44.740002 22.760000 active
2015-11-15 08:40:53.696084 44.740002 22.760000 active

In [7]:
# Create a trend with multiple points using the DataFrame

lst = ['nvoAI1', 'nvoAI2']


fx.df(lst).resample('1min').plot(title='My title')


Out[7]:
<matplotlib.axes._subplots.AxesSubplot at 0x85f66a0>

In [8]:
fx.chart(lst, title='My title')


Out[8]:
<matplotlib.axes._subplots.AxesSubplot at 0x8d59978>

In [9]:
fx.notes = 'New note to remember'
fx.notes


Out[9]:
2015-11-15 08:40:31.226769    Controller initialized
2015-11-15 08:41:19.349162      New note to remember
dtype: object

In [10]:
fx


Out[10]:
FX14 0005

Finding devices on a network


In [ ]:
bacnet.whois() # Note that this function is called automatically in ReadWriteScript

# The result takes a few milliseconds to be processed... it can be used in the same cell.

Using the bacnet object to read or write objects from devices

Accessing the list of object of a device can be done using the objectList property


In [ ]:
# Let's print the first 10 objects...
bacnet.read('2:5 device 5 objectList')[:10]

In [ ]:
bacnet.readMultiple('2:5 analogInput 1 objectName description presentValue units')

In [ ]:
import time
obj = '2:5 analogValue 41 presentValue'
old_value = bacnet.read(obj)
print('Old Value is : %s' % old_value)
new_value = 120

bacnet.write('%s %s' % (obj,new_value))
print('New value is %s' % bacnet.read(obj))

Stopping the app


In [ ]:
bacnet.disconnect()