fh1ch / node-bacstack

A BACnet protocol stack written in pure JavaScript
MIT License
170 stars 97 forks source link

No way to address specific deviceId #48

Open djok opened 7 years ago

djok commented 7 years ago

First, great work.

Currently read and write functions do addressing by IP, but there is a case when one IP address is a gateway to many deviceIds.

Sample whoIs output: address: 10.10.10.100 - deviceId: 1603003 - maxAdpu: 1476 - segmentation: 3 - vendorId: 16 address: 10.10.10.100 - deviceId: 1603017 - maxAdpu: 1476 - segmentation: 3 - vendorId: 16 address: 10.10.10.100 - deviceId: 1603006 - maxAdpu: 1476 - segmentation: 3 - vendorId: 16 address: 10.10.10.100 - deviceId: 1603004 - maxAdpu: 1476 - segmentation: 3 - vendorId: 16 address: 10.10.10.100 - deviceId: 1603005 - maxAdpu: 1476 - segmentation: 3 - vendorId: 16 address: 10.10.10.100 - deviceId: 1603010 - maxAdpu: 1476 - segmentation: 3 - vendorId: 16 address: 10.10.10.100 - deviceId: 1603007 - maxAdpu: 1476 - segmentation: 3 - vendorId: 16

In this case there is no way to address specific deviceId for read/write operation.

Is there solution for this case?

vbr,

fh1ch commented 7 years ago

Hi @djok

First, great work.

Thank you very much :blush:

Am I right with the assumption that you're using BACNET BBMD routing in your network? This is an extension in the BACNET NPDU layer to send telegrams into another BACNET network via router. The special thing is that WhoIs/IAm telegrams are transparently forwarded to all subnets transparently (client doesn't have to implement anything) while all other services have to implement routing explicitly.

Node BACstack currently doesn't support routing as the implementation in the NPDU layer isn't finished yet and also exposing the network and device selection isn't exposed into the client API. I have currently also no setup to verify the implementation of this feature.

Does this info already help you? Would you be interested in testing a possible implementation of this feature?

Cheers

ryanluton commented 6 years ago

@fh1ch I would be happy to assist in the testing of this. I also might be able to set up a remote bbmd address for you to hit with some controllers behind it. Would be happy to chat more on the subject outside of github comments.

fh1ch commented 6 years ago

@ryanluton awesome, thank you very much for this offer, I really appreciate this 👍

I sadly haven't found time lately to push this topic further, but should be able to come up with more progress in this topic in around a month.


Would be happy to chat more on the subject outside of github comments.

Sure, do you have a proposal regarding the format? Would Something like a Gitter channel for this project make sense?

scottc385 commented 6 years ago

@fh1ch @ryanluton I ran into the same whois issue and I think I fixed one problem.

The whois function calls baNpdu.encode() with 'address' and address is expected to be a an object in the form of: { adr: 'xxx.xxx.xxx.xxx', net:0xffff }. However, the whois function later calls transport.send() with address and address is expected to be an ip address string.

I changed the call to transport.send() to pass address.adr and I pass an address object into the whois function. This allowed me to specify the bacnet network ID and find all of the devices on the subnet.

There seems to be an incomplete design regarding addresses. In some places it just wants the ip address string. In other place it wants an object that contains the ip address, bacnet address and (maybe) the deviceID.

I am no bacnet expert, but I would be happy to help with the development. But before I go messing things up, I would like understand the intent of the design. Let me know if you are interested in some help.

Scott

fh1ch commented 6 years ago

Hi @scottc385

Thanks for your input.

Yes, I'm aware of this problem, since the issue you describing was implemented somewhat on purpose, since didn't really have a use-case for BBMD routing, but still liked to have the NPDU layer as complete as possible and leave room for future implementation of it (still haven't found the time tough 😄). Therefore, yes the design and implementation is indeed incomplete.

I would be more than happy to get some help on this topic, one doesn't have to be a BACNET expert at all. Especially if you have a network with BACNET routing at your hands (for verification purpose), it would be awesome to get some support. 👍

Cheers

shortyishere commented 5 years ago

Hi fh1ch

I am somewhat a bacnet expert and have multiple ip routable devices at hand and would love to test and help with this and also am a somewhat programmer. Can we start doing this?

NateZimmer commented 5 years ago

I'm going to take a stab at implementing this for this is some vital functionality. The library is fairly well written for this expansion. I've been able to get read/write/whois working with IP + deviceId addressing. However, fixing segmentation is going take a bit of work. Hopefully on completion the author may have a bit of time to merge it back in.

shortyishere commented 5 years ago

A lot of companies do not use segmentation and there driver is suppose to turn it off by setting a value...

Randolph J. Short

On Jan 14, 2019, at 7:02 AM, Nathan Zimmerman notifications@github.com wrote:

I'm going to take a stab at implementing this for this is some vital functionality. The library is fairly well written for this expansion. I've been able to get read/write/whois working with IP + deviceId addressing. However, fixing segmentation is going take a bit of work. Hopefully on completion the author may have a bit of time to merge it back in.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

NateZimmer commented 5 years ago

@shortyishere if you could test my release once I send it out, that would be cool. Right now i'm trying to muddle my way through the release & testing of this repo for i'm not amazing with node.

Regarding segmentation, some companies use it fairly frequently. Segmentation is fairly simple to implement and it allows one to send & assemble large packets. For example, an object list(77) or all properties(8) could be a rather large packet and segmentation makes transmitting those packets feasible. Library wise, in this case, its just a bit more to implement.

shortyishere commented 5 years ago

I have multiple bacnet devices right in my house I can test while i lay in bed lol of course I will

Shortyishere


From: Nathan Zimmerman notifications@github.com Sent: Monday, January 14, 2019 7:11:02 AM To: fh1ch/node-bacstack Cc: shortyishere; Mention Subject: Re: [fh1ch/node-bacstack] No way to address specific deviceId (#48)

@shortyisherehttps://github.com/shortyishere if you could test my release once I send it out, that would be cool. Right now i'm trying to muddle my way through the release & testing of this repo for i'm not amazing with node.

Regarding segmentation, some companies use it fairly frequently. Segmentation is fairly simple to implement and it allows one to send & assemble large packets. For example, an object list(77) or all properties(8) could be a rather large packet and segmentation makes transmitting those packets feasible. Library wise, in this case, its just a bit more to implement.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/fh1ch/node-bacstack/issues/48#issuecomment-454037997, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AGANmMT7q0jI9u6P8luwujv3M8HxsZ7cks5vDJ4GgaJpZM4O02ET.

shortyishere commented 5 years ago

Also yes some do and some do not at all...it depends how big a network is..and what you are moving around. I can see cases for each segmentation type.

NateZimmer commented 5 years ago

Going to be awhile before I can try to pull it in & clean it up. Source: https://github.com/NateZimmer/node-bacstack/ NPM: https://www.npmjs.com/package/natezimmer_bacstack

Basically address/ip can either be a string: e.g.'192.168.0.23' or an object {ip:'192.168.0.23', net:2001, adr: [5]}. Only use the object in the MSTP/router cases and specify an ip, net and adr. Note, adr is not required for whois.

First try to do whoIs to see if you can find your new devices:

 client.whoIs({'address':{'net':0xFFFF,'ip':'255.255.255.255'}});

Note, sometimes devices are picky and want an address like: 192.168.0.255 <-- where only last 3 are 255.

Here is a readProperty example:

client.readProperty( {'ip':'192.168.1.166','net':2000,'adr':[9]} , {type: 8, instance: 532663}, 85, (err, value) => {
  console.log('value: ', value);
});

I tested this for whois, rp, rpm, wp, and wpm. Also should work with segmentation.

adam-nielsen commented 5 years ago

I'm a bit late to this discussion, but I've almost finished a more functional BBMD support which I think will address this issue.

The problem is that you cannot have multiple BACnet device IDs on the same IP address, on the same port. The example in the first post above is when talking to a BBMD (BACnet proxy server) and in this case each response comes back as a "forwarded NPDU", which includes the remote IP address of the node that owns that IP address (which is currently ignored by this library). So technically the device IDs are not on the same IP address, as you have the unique remote IP address for each device ID, along with the IP of the proxy server you need to communicate with in order to access those remote nodes.

So when you want to address one of those IDs, you send the packet to the BBMD's IP address, but you send it as a FORWARDED_NPDU with the target node's IP address you found from your original whoIs request. The BBMD then forwards the packet on to the IP address you specified.

For example:

Unfortunately I didn't end up using the code from @NateZimmer as I didn't realise that I was working toward the same goal until after I had finished! However my focus was more on creating a BACnet server rather than a client. It does look like we went about the issue in a similar way, by changing the IP address so that it is no longer a string but rather an object. However I had to do things like modify the iAmResponse function to take an address parameter, as you need to be able to send that message to a BBMD if you are responding to a remote node's whoIs - you can't just reply with a broadcast like normal.

I don't have any devices that use segmentation that I can find, so I will have a look at the code from @NateZimmer to see what I have to do to get that working, as I've omitted that for the moment.

The code in question is in the master branch in my fork if anyone is interested: https://github.com/adam-nielsen/node-bacstack

SamuelToh commented 4 years ago

I managed to get some results off @adam-nielsen 's work. Great job guys.

@NateZimmer I'm a bacnet 1 day old newbie. Care to enlighten me what is this array adr for?

Apollon77 commented 4 years ago

These changes should also be incorporated int https://github.com/BiancoRoyal/node-bacstack, please try this package and open issues at https://github.com/BiancoRoyal/node-bacstack/issues if it does not work as expected

NubeDev commented 4 years ago

I managed to get some results off @adam-nielsen 's work. Great job guys.

@NateZimmer I'm a bacnet 1 day old newbie. Care to enlighten me what is this array adr for?

MAC address – On MS/TP networks, this is the eight bit address used to identify devices on a single RS-485 subnet. More info here http://www.bacnet.org/Bibliography/ES-1-97/ES-1-97.htm

Code example for that works on this branch through an IP ro MS/TP router https://github.com/BiancoRoyal/node-bacstack

bacnetClient.whoIs({'net':3});
// read a point through a router to an MSTP device
bacnetClient.readProperty({address: '192.168.15.137',net:3,adr:[6]} , {type: 1, instance: 1}, 85, (err, value) => {
  console.log('value: ', value);
  console.log('err: ', err);
});
heidimao commented 11 months ago

Hello, We also have similar issue that we need to specify address, net and maxSegments, maxApdu to work with some vendors. We use @NateZimmer's fork successfully, thanks. Is there any plan to implement this feature in the near future?