JoelBender / BACpypes3

BACnet communications library
33 stars 7 forks source link

Unable to detect the bacpypes3 based application in linux #34

Closed shashankgowdasd closed 3 months ago

shashankgowdasd commented 3 months ago

Hi @JoelBender Sir, I have simulated the bacpypes3 based application in windows and able to detect in the YABE and BDT( BACnet Discovery Tool by Contemporary Controls) but I am unable to detect when I run the linux environment, So Do I need to make any changes or add any packages to detect the application.

And application runs without bugs but doesn't recognized by the YABE or BDT( BACnet Discovery Tool).

I have also checked running the https://github.com/JoelBender/BACpypes3/blob/main/sandbox/event-server-avo2.py but also unable to recognize in linux environment and I have cloned the latest version of bacpypes3 0.0.88 from github

So please let me know the changes I need to make for my application

ChristianTremblay commented 3 months ago

Be sure your firewall allow UDP 47808

shashankgowdasd commented 3 months ago

Hi @ChristianTremblay, @JoelBender,

Yeah i checked all the network settings as well as firewall also.

More over I've tried with different Linux system with different versions( Ubuntu 22.04.02 and Ubuntu 22.04.04) although unable to detect the device.

JoelBender commented 3 months ago

Time to "go deep" and find out what's happening on the wire. Run something like Wireshark or one of its brother/sister applications like tshark with a capture filter 'udp and port 47808'. When you run the module python3 -m bacpypes3 --address=1.2.3.4/24 you should be able to at least send and receive Who-Is and I-Am traffic. If necessary add a --debug bacpypes3.ipv4 on the end and you'll see everything the application is receiving.

If you can see a local broadcast on the wire but not in the application, I suspect that the address it is actually listening on isn't what you expected, or /24 part is missing from your address specification so sending and receiving unicast traffic would work but not broadcast traffic.

shashankgowdasd commented 3 months ago

Hi @JoelBender Sir, Using tshark I am able to see the broadcasted packets like WhoIs can be seen, but unable to send back the response "I am", from the application and i have corrected IP address with /24.

Below is my application, is this the correct way to use the ip address and let me know the proper way to initialize the IP address

import asyncio
import re
from copy import copy

from typing import Callable, Optional

from bacpypes3.debugging import ModuleLogger, bacpypes_debugging
from bacpypes3.argparse import SimpleArgumentParser
from bacpypes3.console import Console
from bacpypes3.cmd import Cmd
from bacpypes3.comm import bind
from bacpypes3.pdu import Address
from bacpypes3.primitivedata import ObjectIdentifier
from bacpypes3.basetypes import (
    Destination,
    EngineeringUnits,
    EventState,
    LimitEnable,
    NotifyType,
    PropertyIdentifier,
    Recipient,
    TimeStamp,
)
from bacpypes3.object import (
    NotificationClassObject,
)

# from bacpypes3.app import Application,
from bacpypes3.local.analog import AnalogValueObjectIR
from bacpypes3.ipv4.app import Application, NormalApplication
from BACnet_Services.ReadWriteServices import SingleReadWritePropertyServices
from BACnet_Services.ReadWriteMultipleServices import MultipleReadWriteServices
from BACnet_Services.COVServices import COVServices
from BACnet_Services.DeviceServices import CustomDeviceServices

class CustomApplication(
    # Application,
    NormalApplication,
    SingleReadWritePropertyServices,
    MultipleReadWriteServices,
    COVServices,
    CustomDeviceServices,
):
    pass

async def bacnet_application() -> None:
   try:
        this_device = DeviceObject(
            objectIdentifier=("device", 1111),
            objectName="XYZ",
            vendorIdentifier=1111,
            vendorName = "XYZ",
            # protocolObjectTypesSupported=ObjectTypesSupported([])
        )
        app = CustomApplication(device_object=this_device, local_address="192.168.0.112/24")

        avo1 = AnalogValueObjectIR(
            objectIdentifier="analog-value,1",
            objectName="avo1",
            description="test analog value",
            presentValue=50.0,
            eventState=EventState.normal,
            # statusFlags=[0, 0, 0, 0],  # inAlarm, fault, overridden, outOfService
            outOfService=False,
            units=EngineeringUnits.degreesFahrenheit,
            # OUT_OF_RANGE Event Algorithm
            # eventType=EventType.outOfRange,
            timeDelay=10,
            notificationClass=1,
            highLimit=100.0,
            lowLimit=0.0,
            deadband=5.0,
            limitEnable=[1, 1],  # lowLimitEnable, highLimitEnable
            eventEnable=[1, 1, 1],  # toOffNormal, toFault, toNormal
            ackedTransitions=[0, 0, 0],  # toOffNormal, toFault, toNormal
            notifyType=NotifyType.alarm,  # event, ackNotification
            eventTimeStamps=[
                TimeStamp(time=(255, 255, 255, 255)),
                TimeStamp(time=(255, 255, 255, 255)),
                TimeStamp(time=(255, 255, 255, 255)),
            ],
            eventMessageTexts=["", "", ""],
            # eventMessageTextsConfig=[
            #     "to off normal - {pCurrentState}",
            #     "to fault",
            #     "to normal",
            # ],
            eventDetectionEnable=True,
            # eventAlgorithmInhibitReference=ObjectPropertyReference
            eventAlgorithmInhibit=False,
            timeDelayNormal=2,
        )
        if _debug:
            _log.debug("avo1: %r", avo1)

        app.add_object(avo1)

        # notification class
        nc1 = NotificationClassObject(
            objectIdentifier="notification-class,1",
            objectName="nc1",
            description="test notification class",
            notificationClass=1,
            priority=[9, 9, 9],  # toOffNormal, toFault, toNormal priority
            ackRequired=[0, 0, 0],  # toOffNormal, toFault, toNormal
            recipientList=[
                Destination(
                    validDays=[1, 1, 1, 1, 1, 1, 1],
                    fromTime=(0, 0, 0, 0),
                    toTime=(23, 59, 59, 99),
                    recipient=Recipient(device="device,990"),
                    processIdentifier=0,
                    issueConfirmedNotifications=True,
                    transitions=[1, 1, 1],  # toOffNormal, toFault, toNormal
                )
            ],
        )
        if _debug:
            _log.debug("nc1: %r", nc1)

        app.add_object(nc1)

       await asyncio.Future()

if __name__ == "__main__":
        await bacnet_application() 
JoelBender commented 3 months ago

Thank you for posting the code, there are a few things to change. You can see examples of this with the start_here.py sample application.

  1. Replace the from bacpypes3.ipv4.app import Application, NormalApplication with from bacpypes3.app import Application.
  2. You no longer need to import the services explicitly, all of them are bundled in, see this code.
  3. Replace the await bacnet_application() with asyncio.run(bacnet_application())
  4. When you create an instance of an application from an object list you use something like app = Application.from_object_list([this_device]) but you also have to create a NetworkPortObject. The simplest way to get a configuration is to run the module interactively and dump its configuration as a JSON blob:
    $ python3 -m bacpypes3 --address 192.168.0.112/24
    > config json
shashankgowdasd commented 3 months ago

Thanks @JoelBender Sir, For such a satisfying explanation and My application is able to be detected by the YABE now sir...