У меня 2 компьютера:
- На первом я хочу запустить файл .py для имитации нескольких устройств BACnet на моем компьютере. IP-адрес: 192.168.1.54/24, порт = BAC0 (47808)
- На втором, в той же подсети, я хочу визуализировать свои устройства, подключившись к YABE (еще один BACnet Explorer) со следующей конфигурацией: «BACnet/IP V4 & V6 over Udp» port = BAC0 и Local endpoint = 192.168.1.38
Код: Выделить всё
#!/usr/bin/env python3
"""
BACnet device with custom objects - Fixed version => Mahé can see my 2 variables on his PC using YABE!
"""
import asyncio
from BAC0 import lite
from bacpypes3.local.analog import AnalogValueObject, AnalogInputObject
from bacpypes3.primitivedata import Real, ObjectIdentifier
from bacpypes3.basetypes import EngineeringUnits
async def main():
try:
print("🚀 Starting BACnet device with objects...")
# Create BACnet device
bacnet_device = lite(ip="192.168.1.54/24", deviceId=1234)
# Access underlying bacpypes3 application to create objects
app = bacnet_device.this_application.app
# Create BACnet objects
temp_sensor = AnalogValueObject(
objectIdentifier=ObjectIdentifier("analogValue,1"),
objectName="Room_Temperature",
presentValue=Real(22.5),
units=EngineeringUnits.degreesCelsius,
description="Temperature sensor",
)
app.add_object(temp_sensor)
pressure_sensor = AnalogInputObject(
objectIdentifier=ObjectIdentifier("analogInput,2"),
objectName="Room_Pressure",
presentValue=Real(1013.25),
units=EngineeringUnits.pascals,
description="Pressure sensor",
)
app.add_object(pressure_sensor)
print("✅ BACnet device with objects created!")
print(" Device ID: 1234")
print(" Address: 192.168.2.110/24")
print(" Created objects:")
print(f" - {temp_sensor.objectName}: {temp_sensor.presentValue} °C")
print(f" - {pressure_sensor.objectName}: {pressure_sensor.presentValue} Pa")
print("\n🔍 Scan with YABE to see objects")
# Keep running
await asyncio.Future()
except KeyboardInterrupt:
print("\n🛑 Stopped")
except Exception as e:
print(f"❌ Error: {e}")
finally:
if 'bacnet_device' in locals():
await bacnet_device.disconnect()
if __name__ == "__main__":
asyncio.run(main())
Код: Выделить всё
(xml_3_13) PS C:\Users\POTIEAL\Documents\RetD\m2524238-convertisseur_xml_danfoss> python .\test_bacnet_BAC0_eng.py
🚀 Starting BACnet device with objects...
2026-03-27 17:05:07,682 - INFO | Starting Asynchronous BAC0 version 2025.09.15 (Lite)
2026-03-27 17:05:07,682 - INFO | Using bacpypes3 version 0.0.106
2026-03-27 17:05:07,682 - INFO | Use BAC0.log_level to adjust verbosity of the app.
2026-03-27 17:05:07,682 - INFO | Ex. BAC0.log_level('silence') or BAC0.log_level('error')
2026-03-27 17:05:07,762 - INFO | Using ip : 192.168.1.54/24 on port 47808 | broadcast : 192.168.1.255
2026-03-27 17:05:08,394 - INFO | Using default JSON configuration file
2026-03-27 17:05:08,400 - INFO | Registered as BACnet/IP App | mode normal
2026-03-27 17:05:08,401 - INFO | Device instance (id) : 1234
✅ BACnet device with objects created!
Device ID: 1234
Address: 192.168.2.110/24
Created objects:
- Room_Temperature: 22.5 °C
- Room_Pressure: 1013.25 Pa
🔍 Scan with YABE to see objects
2026-03-27 17:05:08,402 - INFO | Installing recurring task Ping Registered Devices Task (id:2480079317248)
2026-03-27 17:05:08,405 - INFO | Installing recurring task Cleanup Tasks List (id:2480079430160)

Но когда я попытался создать другое устройство:
- используя BAC0 и пытаясь установить другой экземпляр BAC0.lite, я получено:
BAC0.core.io.IOExceptions.InitializationError: предоставленный IP-адрес (192.168.49.110) недействителен. Проверьте, не использует ли другое программное обеспечение порт 47808 на этом сетевом интерфейсе. Если да, вы можете определить несколько IP-адресов для каждого интерфейса. Или укажите другой IP с помощью BAC0.lite(ip='IP/mask') - Я также пробовал напрямую работать с bacpypes3 вместо BAC0 с такими объектами, как:
однако я был ошеломлен, поскольку попробовал дюжину вариантов и получил такие ошибки, как:
Код: Выделить всё
from bacpypes3.vlan import Network as VirtualNetwork, Node as VirtualNodeпри исполнении илиКод: Выделить всё
File "C:\Users\POTIEAL\Documents\RetD\m2524238-convertisseur_xml_danfoss\venv\xml_3_13\Lib\site-packages\bacpypes3\netservice.py", line 576, in bind raise RuntimeError("already bound: %r" % (net,))при получении whois() со 2-го компьютера..Код: Выделить всё
raise ConfigurationError("unbound server") bacpypes3.comm.ConfigurationError: unbound server
РЕДАКТИРОВАТЬ: один из полных сценариев (не работает) для 2+ (10 с цикл) виртуальные устройства:
Код: Выделить всё
import asyncio
import logging
import sys
# Pure bacpypes3 imports
from bacpypes3.pdu import IPv4Address, LocalStation, LocalBroadcast
from bacpypes3.comm import bind
from bacpypes3.app import Application
from bacpypes3.appservice import ApplicationServiceAccessPoint
from bacpypes3.local.device import DeviceObject
from bacpypes3.local.analog import AnalogValueObject
from bacpypes3.netservice import NetworkServiceAccessPoint, NetworkServiceElement
from bacpypes3.vlan import Network as VirtualNetwork, Node as VirtualNode
from bacpypes3.ipv4.link import NormalLinkLayer
# Logging configuration
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
_log = logging.getLogger("BACnetGateway")
async def main():
# --- NETWORK CONFIGURATION ---
HOST_IP = "192.168.1.54/24"
PHYS_NET = 1
VIRT_NET = 10001
_log.info(f"Starting gateway on {HOST_IP}...")
# --- 1. VIRTUAL NETWORK CONFIGURATION (VLAN) ---
vlan = VirtualNetwork(name="VLAN10001", broadcast_address=LocalBroadcast())
# --- 2. ROUTER CONFIGURATION (Bridge) ---
# The router NSAP handles forwarding between PHYS_NET and VIRT_NET
router_nsap = NetworkServiceAccessPoint()
router_nse = NetworkServiceElement()
bind(router_nse, router_nsap)
# Physical interface binding (IP side)
phys_addr = IPv4Address(HOST_IP)
phys_link = NormalLinkLayer(phys_addr)
# We use .bind() from NSAP to attach the physical link
router_nsap.bind(phys_link, net=PHYS_NET, address=phys_addr)
# Virtual interface binding (VLAN side)
router_vmac = LocalStation(0)
router_vlan_node = VirtualNode(router_vmac, vlan)
# The router is present on the VLAN with MAC 0
router_nsap.bind(router_vlan_node, net=VIRT_NET, address=router_vmac)
_log.info(f"Router configured: Network {PHYS_NET} Network {VIRT_NET}")
# --- 3. CREATION OF 10 VIRTUAL TERMINALS ---
terminals = []
for i in range(1, 11):
dev_id = 100 + i
vmac = LocalStation(i)
device_info = DeviceObject(
objectIdentifier=("device", dev_id),
objectName=f"Virtual_Terminal_{dev_id}",
vendorIdentifier=999,
)
# Creation of BACnet stack for this terminal
app = Application(device_info)
asap = ApplicationServiceAccessPoint(device_info, app.device_info_cache)
device_nsap = NetworkServiceAccessPoint()
device_nse = NetworkServiceElement()
# Upper layers binding (App -> ASAP -> NSAP)
bind(app, asap, device_nsap)
bind(device_nse, device_nsap)
# Binding to lower layer (VLAN) via NSAP.bind()
device_node = VirtualNode(vmac, vlan)
device_nsap.bind(device_node, address=vmac)
# Adding Temperature object
app.add_object(
AnalogValueObject(
objectIdentifier=("analogValue", 1),
objectName="Temperature",
presentValue=20.0 + i,
units="degreesCelsius"
)
)
terminals.append(app)
_log.info(f"Terminal {dev_id} ready on VLAN (MAC {i})")
# Initial announcement (synchronous, no await)
app.i_am()
_log.info("--- System ready. Scan with YABE (Who-Is Global) ---")
# Infinite keep-alive loop
try:
while True:
# We send periodic I-Am to maintain visibility in YABE
for app in terminals:
app.i_am()
await asyncio.sleep(60)
except asyncio.CancelledError:
_log.info("Task cancelled.")
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
_log.info("Simulation interrupted by user.")