bacnetctrl

package
v0.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 7, 2026 License: MIT Imports: 14 Imported by: 0

README

BACnet controller

Configuration

Example (add under controllers.bacnet in your app config):

controllers:
  bacnet:
    enabled: true
    addr: "0.0.0.0:47808"    # BACnet/IP UDP listen address
    device_instance: 1        # BACnet device instance number (0..4194303)
    sync_interval: 0.5s       # Retained for parity; currently unused

Environment variables:

Variable Description
TMK_CONTROLLER Set to bacnet to start only the BACnet controller
TMK_ADDR Override addr (e.g. 127.0.0.1:47808)
TMK_CONTROLLERS_BACNET_DEVICE_INSTANCE Override device instance number

BACnet interface

The controller implements BACnet/IP over UDP and handles three services:

  • Who-Is / I-Am — Responds to Who-Is broadcasts with an I-Am containing the configured device instance.
  • ReadProperty — Returns PresentValue (property 85) for all supported objects.
  • WriteProperty — Sets PresentValue for writable objects. Returns SimpleACK on success, Error on failure.

Only PresentValue (property ID 85) is supported. Requests for other properties receive an Error response.

PresentValue is encoded with the BACnet datatype that matches the object type — Real for Analog objects, Enumerated for Binary Value, and Unsigned for Multi-State Value — so a conformant client (e.g. bacpypes3) decodes each object with its expected datatype. A write must use that same datatype; a value of any other datatype is rejected with an invalid-data-type error rather than coerced.

Object mapping

BACnet Object Instance Variable Access
Analog Input (0) 0 ambient_temperature Read-only
Analog Value (2) 0 temperature_setpoint Read / Write
Analog Value (2) 1 temperature_setpoint_min Read / Write
Analog Value (2) 2 temperature_setpoint_max Read / Write
Analog Value (2) 3 fault_code Read / Write
Binary Value (5) 0 enabled Read / Write
Multi-State Value (19) 0 mode Read / Write
Multi-State Value (19) 1 fan_speed Read / Write
Value encoding
  • Temperatures (AI:0, AV:0, AV:1, AV:2): Real — IEEE 754 float32 in degrees Celsius.
  • Fault Code (AV:3): Real — integer transported as float32 (truncated to int on write).
  • Enabled (BV:0): Enumerated — 1 = active, 0 = inactive.
  • Mode (MSV:0): Unsigned — 1 = heat, 2 = cool, 3 = fan, 4 = auto.
  • Fan Speed (MSV:1): Unsigned — 1 = auto, 2 = low, 3 = medium, 4 = high.

Error handling

  • Reading or writing an unknown object returns ErrorClassObject / ErrorCodeUnknownObject.
  • Writing to a read-only object (Analog Input) returns ErrorClassService / ErrorCodeServiceRequestDenied.
  • Writing a value whose datatype doesn't match the object type returns ErrorClassProperty / ErrorCodeInvalidDataType.
  • Requesting a property other than PresentValue returns ErrorClassService / ErrorCodeServiceRequestDenied.

Known library issues

This controller uses github.com/ulbios/bacnet. Two bugs in the library are worked around in the controller code:

  1. IAmObjects ignores the device instance parameter — hardcodes instance 321. The controller builds I-Am objects manually.
  2. DecObjectIdentifier bit-shift error — uses >> 20 instead of >> 22, causing object types to decode as type * 4. The controller implements its own decoders.

See also

Documentation

Index

Constants

View Source
const (
	ObjectTypeAnalogValue     uint16 = 2
	ObjectTypeBinaryValue     uint16 = 5
	ObjectTypeMultiStateValue uint16 = 19
)

BACnet object types not defined in the library.

View Source
const (
	ErrorClassProperty       uint8 = 2
	ErrorCodeInvalidDataType uint8 = 9
)

BACnet error class/code not defined in the library.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Identity
	DeviceID       string
	DeviceInstance int // BACnet device instance number (0..4194303)

	// Network
	Addr string // bind address, e.g. "0.0.0.0:47808" or "127.0.0.1:0" for ephemeral port in tests

	// Behavior
	SyncInterval time.Duration // retained for parity; unused by WhoIs handling
}

Config for the BACnet controller.

type Controller

type Controller struct {
	// contains filtered or unexported fields
}

func New

func New(svc thermostat.Service, cfg Config, logger *slog.Logger) (*Controller, error)

New creates a BACnet controller. DeviceInstance must be in the BACnet range 0..4194303.

func (*Controller) LocalAddr

func (c *Controller) LocalAddr() net.Addr

LocalAddr returns the controller's bound address (useful for tests).

func (*Controller) Run

func (c *Controller) Run(ctx context.Context) error

Run starts a BACnet/IP listener and handles Who-Is, ReadProperty, and WriteProperty. It blocks until ctx is canceled.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL