BACnet的读写服务 (六)

8 篇文章 1 订阅


今天来捋一捋BACnet的读写服务,自己动手写一个小Demo,能够读取Bacnet.Room.Simulator的数据。
先看一下效果图
请添加图片描述

大体思路

先发现BACnet设备,发现的设备记录在左上角的树中, 点击设备后能够获取该设备的所有对象,用左下角的树形显示。 选中某个对象后,再点读取,右边的方框输出读写日志。

发现BACnet设备

首先我们创建一个BACnet对象,用其来发现设备。

RWServices.cs 辅助类,定义了一个BACnet对象,以及声明了存储发现的BACnet设备的字典。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.IO.BACnet;

namespace RW_BacnetClient
{
    public  static class RWServices
    {
        public static BacnetClient m_service;

        public static Dictionary<BacnetAddress, BacnetLine> clients
            = new Dictionary<BacnetAddress, BacnetLine>();

       
    }

    public class BacnetLine
    {
        public BacnetClient client;
        public uint deviceId;

       public BacnetLine()
        {

        }

        public BacnetLine(BacnetClient client, uint deviceId)
        {
            this.client = client;
            this.deviceId = deviceId;
        }
    }
}

主界面代码初始化,初始化设备树,以及发现设备。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.IO.BACnet;
using System.IO.BACnet.Base;
using System.Threading;

namespace RW_BacnetClient
{
    public partial class Form1 : Form
    {

        TreeNode deviceRoot;

        public Form1()
        {
            InitializeComponent();
            InitUI();
            Init();
            RegisterEvent();
        }

        //界面初始化
        private void InitUI()
        {
            treeDevice.ImageList = imageList1;
            deviceRoot = new TreeNode("根", 0, 0);
            treeDevice.Nodes.Add(deviceRoot);

            treeProperty.ImageList = imageList1;
        }

        private void Init()
        {
            RWServices.m_service = new BacnetClient(
                new BacnetIpUdpProtocolTransport(47808, false));

            RWServices.m_service.OnIam -= M_service_OnIam;
            RWServices.m_service.OnIam += M_service_OnIam;

            //启动
            RWServices.m_service.Start();
            //广播 谁在
            RWServices.m_service.WhoIs();

        }
      

        //事件注册
        private void RegisterEvent()
        {
            btnWhoIs.Click += BtnWhoIs_Click;
            btnRead.Click += BtnRead_Click;
            btnReadMutil.Click += BtnReadMutil_Click;
            btnSubscribe.Click += BtnSubscribe_Click;
            btnWrite.Click += BtnWrite_Click;

            treeDevice.NodeMouseClick += TreeDevice_NodeMouseClick;
            
            treeProperty.NodeMouseClick += TreeProperty_NodeMouseClick;
        }

       
        #region Helper Method

        private void Log(string str)
        {
            this.BeginInvoke(new Action(() =>
            {
                this.txt_MsgList.AppendText($"{System.DateTime.Now.ToString("HH:mm:ss")}: {str}\r\n");
                 
            }));
        }


        private void ShowText(string str)
        {
            this.BeginInvoke(new Action(() =>
            {
                this.txt_MsgList.AppendText(str + "\r\n");
            }));
        }

        #endregion

        /// <summary>
        /// 响应Iam
        /// </summary>
        private void M_service_OnIam(BacnetClient sender, BacnetAddress adr, uint deviceId, uint maxAPDU, BacnetSegmentations segmentation, ushort vendorId)
        {
            if (RWServices.clients.ContainsKey(adr)) return;
            RWServices.clients[adr] = new BacnetLine(sender, deviceId);  //记录新添加的BACnet设备
            sender.OnCOVNotification += Sender_OnCOVNotification; ;
          

            this.BeginInvoke(new Action(() =>
            {//添加到设备树上
                TreeNode node = new TreeNode(adr.ToString() + ":" + deviceId, 1, 1);
                node.Tag = adr;
                deviceRoot.Nodes.Add(node);

            }));
        }

读取设备的所有对象

像Yabe一样,获取BACnet设备的所有对象,应该如何获取呢?
在这里插入图片描述
当然也是使用ReadPropertyRequest服务,读取设备对象BacnetObjectTypes.OBJECT_DEVICE,读整个对象列表 BacnetPropertyIds.PROP_OBJECT_LIST

        /// <summary>
        /// 设备树
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TreeDevice_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (!(e.Node is TreeNode node)) return;
            if (node.Level == 0 || node.Tag == null) return;

            BacnetLine line = RWServices.clients[node.Tag as BacnetAddress];

            ReadDeviceObject(line, (BacnetAddress)(node.Tag));
        }
        
        #region 读取设备的所有对象
        private void ReadDeviceObject( BacnetLine comm, BacnetAddress adr)
        {
            uint device_id = comm.deviceId;
            IList<BacnetValue> ret; // 得到所有的对象
            if (!RWServices.m_service.ReadPropertyRequest(adr,
                new BacnetObjectId(BacnetObjectTypes.OBJECT_DEVICE, device_id),
                BacnetPropertyIds.PROP_OBJECT_LIST, out ret)) 
            {
               Log("Didn't get response from 'Structured Object List'");
                return;
            }

            List<BacnetObjectId> listObj = SortBacnetObjects(ret);

            this.BeginInvoke(new Action(() =>
            {
                this.treeProperty.Nodes.Clear();

                foreach(BacnetObjectId ob in listObj)
                {
                    TreeNode node = new TreeNode(ob.ToString(), 2, 2);
                    node.Tag = ob;

                    treeProperty.Nodes.Add(node);
                }
            }));

        }

        //排序
        private List<BacnetObjectId> SortBacnetObjects(IList<BacnetValue> listVal)
        {
            List<BacnetObjectId> sortedList = new List<BacnetObjectId>();

            foreach(BacnetValue val in listVal)
            {
                if(val.Value is BacnetObjectId)
                {
                    sortedList.Add((BacnetObjectId)val.Value);
                }
                else
                {
                    BacnetDeviceObjectPropertyReference v = (BacnetDeviceObjectPropertyReference)val.Value;
                    sortedList.Add(v.objectIdentifier);
                }
            }

            sortedList.Sort();
            return sortedList;
        }
        #endregion

读取设备指定的对象的当前值

如果我们仅读取单一对象的当前值,应该如何读取呢?就比如说读取当前的温度值。
首先当然是找到当前温度值这个对象,然后再去读取当前值(是众多属性中的其中一个)了。
ReadPropertyRequest(adr, objectId, BacnetPropertyIds.PROP_PRESENT_VALUE, out values);

        //读取单个
        private void BtnRead_Click(object sender, EventArgs e)
        {
            if (treeProperty.SelectedNode == null
                || treeDevice.SelectedNode == null)
                return;

            BacnetAddress adr = (BacnetAddress)treeDevice.SelectedNode.Tag;
            if (adr == null) return;
            //找到待读取的对象
            BacnetObjectId objectId = (BacnetObjectId)treeProperty.SelectedNode.Tag ;
           
            if (objectId == null) return;

            IList<BacnetValue> values;
            //读取该对象的当前值
          if(  RWServices.m_service.ReadPropertyRequest(adr, objectId,
                BacnetPropertyIds.PROP_PRESENT_VALUE, out values))
            {
                DataType = values[0].Value.GetType();
                ShowText(objectId.ToString() + ": 读到值:" + values[0].Value.ToString() +
                    " 数据类型:" + DataType +
                    " 转换后的类型:" + Type.GetTypeCode(DataType));
            }

        }

读某个对象下的所有属性Property

读取所有属性ReadPropertyMultipleRequest(adr, objectId, properties, out multi_value_list)

   //读多个属性
        private void BtnReadMutil_Click(object sender, EventArgs e)
        {
            ; if (treeProperty.SelectedNode == null
               || treeDevice.SelectedNode == null)
                return;

            BacnetAddress adr = (BacnetAddress)treeDevice.SelectedNode.Tag;
            if (adr == null) return;
            //找到某个对象id
            BacnetObjectId objectId = (BacnetObjectId)treeProperty.SelectedNode.Tag;

            if (objectId == null) return;

            System.Threading.ThreadPool.QueueUserWorkItem((o =>
            {

                BacnetPropertyReference[] properties = new BacnetPropertyReference[]
                { 
                    new BacnetPropertyReference((uint)BacnetPropertyIds.PROP_ALL,
                     System.IO.BACnet.Serialize.ASN1.BACNET_ARRAY_ALL) 
                };

                IList<BacnetReadAccessResult> multi_value_list;


                if (!RWServices.m_service.ReadPropertyMultipleRequest(adr, objectId,
                      properties, out multi_value_list))
                {
                    Log("读取多个属性失败");
                    return;
                }


                foreach (BacnetPropertyValue p_value in multi_value_list[0].values)
                {
                    object value = null;
                    BacnetValue[] b_values = null;
                    if (p_value.value != null)
                    {

                        b_values = new BacnetValue[p_value.value.Count];

                        p_value.value.CopyTo(b_values, 0);
                        if (b_values.Length > 1)
                        {
                            object[] arr = new object[b_values.Length];
                            for (int j = 0; j < arr.Length; j++)
                                arr[j] = b_values[j].Value;
                            value = arr;
                        }
                        else if (b_values.Length == 1)
                            value = b_values[0].Value;
                    }
                    else
                        b_values = new BacnetValue[0];

                    ShowText("propertyId: " + p_value.property.propertyIdentifier.ToString()+
                            
                             "  properStr:  " + p_value.property.ToString() +
                        " 读到值:" + value.ToString() + 
                        " 数据类型:" + value.GetType().ToString());

                    /* switch ((BacnetPropertyIds)p_value.property.propertyIdentifier)
                     {
                         // PROP_PRESENT_VALUE can be write at null value to clear the prioroityarray if exists
                         case BacnetPropertyIds.PROP_PRESENT_VALUE:
                             // change to the related nullable type
                             Type t = value.GetType();
                             try
                             {
                                 if (t != typeof(String)) // a bug on linuxmono where the folling instruction generates a wrong type
                                     t = Type.GetType("System.Nullable`1[" + value.GetType().FullName + "]");
                             }
                             catch { }

                             break;



                         default:
                             break;
                     }

                     // The Prop Name replace the PropId into the Treenode 
                     if (p_value.property.propertyIdentifier == (byte)BacnetPropertyIds.PROP_OBJECT_NAME)
                     {
                         ShowText(objectId.ToString() + ": 读到值:" + value.ToString());

                     }*/
                }


            }));
        }

改写某个属性的值

要改写某个属性的值,首先要将out_of _service (脱离服务)的值设置为true, 可以先用Yabe设置。
在这里插入图片描述

再用自己写的Demo修改值,当然并不是所有值都可以修改。
在这里插入图片描述
WritePropertyRequest(adr, objectId, BacnetPropertyIds.PROP_PRESENT_VALUE, values) ;
这里需要注意的是,我们需要知道这个属性值的数据类型是什么,(是 float int string bool)才能写成功,如果数据类型对应不上则会失败。

   List<BacnetValue> values = new List<BacnetValue>()
        {
            new BacnetValue (BacnetApplicationTags.BACNET_APPLICATION_TAG_REAL,
            float.Parse( txt_value.Text.Trim()))
        };
         /// <summary>
        /// 写
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnWrite_Click(object sender, EventArgs e)
        {
            if (treeProperty.SelectedNode == null
                || treeDevice.SelectedNode == null)
                return;

            BacnetAddress adr = (BacnetAddress)treeDevice.SelectedNode.Tag;
            if (adr == null) return;

            BacnetObjectId objectId = (BacnetObjectId)treeProperty.SelectedNode.Tag;

            if (objectId == null) return;

            List<BacnetValue> values = new List<BacnetValue>()
            {
                new BacnetValue (BacnetApplicationTags.BACNET_APPLICATION_TAG_REAL,
                float.Parse( txt_value.Text.Trim()))
            };

            try
            {
                if (RWServices.m_service.WritePropertyRequest(adr, objectId,
                      BacnetPropertyIds.PROP_PRESENT_VALUE, values))
                {
                    ShowText(objectId.ToString() + ": 写入成功-值:" + values[0].Value.ToString());
                }
            }
            catch(Exception ex)
            {
                Log("写入失败。。" + ex.Message);
            }
        }

小结

介绍了Bacnet设备的读和写, 读整个设备的对象列表, 读单个对象的某个属性, 读单个对象的所有属性 ReadPropertyRequest;写某个对象的当前值WritePropertyRequest
资源下载地址:https://download.csdn.net/download/weixin_40314351/89156501?spm=1001.2014.3001.5503

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值