Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce new addressing- and telegram-classes #48

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 52 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,20 @@ static void Main(string[] args)
{
var connection = new KnxConnectionRouting();
connection.Connect();
connection.GroupAddressStyle = KnxGroupAddressStyle.ThreeLevel;
connection.KnxEventDelegate += Event;
connection.Action("5/0/2", false);

// Parse GroupAddress from a string
connection.Action(KnxGroupAddress.Parse("5/0/2"), false);
Thread.Sleep(5000);
connection.Action("5/0/2", true);

// Instantiate a three level GroupAddress
connection.Action(new KnxThreeLevelGroupAddress(5, 0, 2), true);
Thread.Sleep(5000);
}
static void Event(string address, string state)
static void Event(object sender, KnxEventArgs args)
{
Console.WriteLine("New Event: device " + address + " has status " + state);
Console.WriteLine($"New Event: device {args.DestinationAddress} has status {args.State}");
}
```

Expand All @@ -54,29 +59,28 @@ static void Event(string address, string state)
Sending an action

```csharp
connection.Action("1/1/16", connection.ToDataPoint("9.001", 24.0f));
connection.Action("1/1/17", connection.ToDataPoint("5.001", 50));
connection.Action(new KnxThreeLevelGroupAddress(1, 1, 16), connection.ToDataPoint("9.001", 24.0f));
connection.Action(KnxGroupAddress.Parse("1/1/17"), connection.ToDataPoint("5.001", 50));
```

Converting state from event

```csharp
static void Event(string address, string state)
static void Event(object sender, KnxEventArgs args)
{
if (address == "1/1/16")
if (args.DestinationAddress.Equals(new KnxThreeLevelGroupAddress(1, 1, 16)))
{
decimal temp = (decimal)connection.FromDataPoint("9.001", state);
Console.WriteLine("New Event: device " + address + " has status " + temp);
decimal temp = (decimal)connection.FromDataPoint("9.001", args.State);
Console.WriteLine($"New Event: device {args.DestinationAddress} has status {temp}");
return;
}
if (address == "1/1/17")
if (args.DestinationAddress.ToString() == "1/1/17")
{
int perc = (int)connection.FromDataPoint("5.001", state);
Console.WriteLine("New Event: device " + address + " has status " + perc);
int perc = (int)connection.FromDataPoint("5.001", args.State);
Console.WriteLine($"New Event: device {args.DestinationAddress} has status {perc}");
return;
}
}

```

### Requesting status
Expand All @@ -85,38 +89,41 @@ Sending an action

```csharp
connection.KnxStatusDelegate += Status;
connection.RequestStatus("1/1/16");
connection.RequestStatus("1/1/17");
connection.RequestStatus(KnxGroupAddress.Parse("1/1/16"));
connection.RequestStatus(KnxGroupAddress.Parse("1/1/17"));
```

Converting state from status event

```csharp
static void Status(string address, string state)
private static void Status(object sender, KnxStatusArgs args)
{
if (address == "1/1/16")
// Process only GroupAddresses (using pattern matching in C# 7.0)
if (!(args.DestinationAddress is KnxGroupAddress groupAddress))
return;

if (groupAddress.Equals(1, 1, 6))
{
decimal temp = (decimal)connection.FromDataPoint("9.001", state);
Console.WriteLine("New Event: device " + address + " has status " + temp);
decimal temp = (decimal)connection.FromDataPoint("9.001", args.State);
Console.WriteLine($"New Status: device {addr} has status {temp}");
return;
}
if (address == "1/1/17")
if (groupAddress.Equals("1/1/17"))
{
int perc = (int)connection.FromDataPoint("5.001", state);
Console.WriteLine("New Event: device " + address + " has status " + perc);
int perc = (int)connection.FromDataPoint("5.001", args.State);
Console.WriteLine($"New Status: device {addr} has status {perc}");
return;
}
}

```

### Sending actions without using datapoints

```csharp
connection.Action("1/1/19", true);
connection.Action("1/1/20", false);
connection.Action("1/1/21", 60);
connection.Action("1/1/22", 0x4E);
connection.Action(KnxGroupAddress.Parse("1/1/19"), true);
connection.Action(KnxGroupAddress.Parse("1/1/20"), false);
connection.Action(KnxGroupAddress.Parse("1/1/21"), 60);
connection.Action(KnxGroupAddress.Parse("1/1/22"), 0x4E);
```

### Connecting using Tunneling
Expand All @@ -127,6 +134,23 @@ The only difference is how the connection object is created
connection = new KNXConnectionTunneling(remoteIP, remotePort, localIP, localPort);
```

### Setting GroupAddressStyle

KNX supports 3 ways to represent GroupAddresses:
* 3-Level: MainGroup/MiddleGroup/SubGroup
* 2-Level: MainGroup/SubGroup
* Free: SubGroup

The used style is not transmitted with the packets and is only an artifical representation of a 2-byte address. To allow KNX.net to correctly translate received addresses you need to specify which style to use:

```csharp
connection.GroupAddressStyle = KnxGroupAddressStyle.ThreeLevel;
connection.GroupAddressStyle = KnxGroupAddressStyle.TwoLevel;
connection.GroupAddressStyle = KnxGroupAddressStyle.Free;
```

KNX.net supports extended group addresses, i.e. full 16 bit addresses.

### Notes

If connecting in routing mode:
Expand Down
47 changes: 47 additions & 0 deletions src/KNXLib/Addressing/KnxAddress.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace KNXLib.Addressing
{
public abstract class KnxAddress
{
public KnxAddress()
{
}

public abstract byte[] GetAddress();
protected abstract void InternalParse(string address);
protected abstract void InternalParse(byte[] address);
public abstract bool IsValid();

public static KnxAddress Parse(string address)
{
if (address.Contains("."))
return KnxIndividualAddress.Parse(address);

return KnxGroupAddress.Parse(address);
}

public bool Equals(string address)
{
return Equals(Parse(address));
}

public override bool Equals(object obj)
{
if (obj is KnxAddress otherAddress)
{
byte[] address1 = GetAddress();
byte[] address2 = otherAddress.GetAddress();

return address1[0].Equals(address2[0]) && address1[1].Equals(address2[1]);

}

return base.Equals(obj);
}

public override int GetHashCode()
{
byte[] address = GetAddress();
return (address[1] << 8) | address[0];
}
}
}
103 changes: 103 additions & 0 deletions src/KNXLib/Addressing/KnxFreeStyleGroupAddress.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using KNXLib.Exceptions;

namespace KNXLib.Addressing
{
public class KnxFreeStyleGroupAddress : KnxGroupAddress
{

public KnxFreeStyleGroupAddress(int subGroup) : base(0, 0, subGroup)
{
}

public KnxFreeStyleGroupAddress(string groupAddress)
{
InternalParse(groupAddress);
}

public KnxFreeStyleGroupAddress(byte[] groupAddress)
{
InternalParse(groupAddress);
}

// +-----------------------------------------------+
// 16 bits | GROUP ADDRESS (FreeStyle) |
// +-----------------------+-----------------------+
// | OCTET 0 (high byte) | OCTET 1 (low byte) |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// bits | 7| 6| 5| 4| 3| 2| 1| 0| 7| 6| 5| 4| 3| 2| 1| 0|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | Sub Group |
// +-----------------------+-----------------------+


public override byte[] GetAddress()
{
if (!IsValid())
throw new InvalidKnxAddressException(ToString());

var addr = new byte[2];

addr[0] = (byte)(SubGroup >> 8);
addr[1] = (byte)(SubGroup);

return addr;
}

public override bool IsValid()
{
// FreeStyle only has a SubGroup
if (MainGroup != 0 || MiddleGroup != 0)
return false;

// Check range for SubGroup 1-65535
if (SubGroup < 1 || SubGroup > 65535)
return false;

return base.IsValid();
}

protected override void InternalParse(string groupAddress)
{
var groupParts = groupAddress.Split('/');

// Check if GA consists of 1 part
if (groupParts.Length != 1)
return;

if (!int.TryParse(groupParts[0], out int subGroup))
return;

MainGroup = 0;
MiddleGroup = 0;
SubGroup = subGroup;
}

protected override void InternalParse(byte[] groupAddress)
{
if (groupAddress.Length != 2)
return;

MainGroup = 0;
MiddleGroup = 0;
SubGroup = ((groupAddress[0] << 8) | groupAddress[1]);
}

public override string ToString()
{
return $"{SubGroup}";
}

public override bool Equals(object obj)
{
if (obj is KnxFreeStyleGroupAddress)
return base.Equals(obj);

return false;
}

public override int GetHashCode()
{
return base.GetHashCode();
}
}
}
82 changes: 82 additions & 0 deletions src/KNXLib/Addressing/KnxGroupAddress.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using KNXLib.Enums;

namespace KNXLib.Addressing
{
public abstract class KnxGroupAddress : KnxAddress
{
public int MainGroup { get; set; }
public int MiddleGroup { get; set; }
public int SubGroup { get; set; }


public KnxGroupAddress()
{
}

public KnxGroupAddress(int mainGroup, int middleGroup, int subGroup)
{
MainGroup = mainGroup;
MiddleGroup = middleGroup;
SubGroup = subGroup;
}

public override bool IsValid()
{
// The GA 0x00 is not allowed
if (MainGroup == 0 && MiddleGroup == 0 && SubGroup == 0)
return false;

return true;
}

public static new KnxGroupAddress Parse(string groupAddress)
{
var groupParts = groupAddress.Split('/');

if (groupParts.Length == 3)
return new KnxThreeLevelGroupAddress(groupAddress);
else if (groupParts.Length == 2)
return new KnxTwoLevelGroupAddress(groupAddress);

return new KnxFreeStyleGroupAddress(groupAddress);
}

public static KnxGroupAddress Parse(byte[] groupAddress, KnxGroupAddressStyle style)
{
if (style == KnxGroupAddressStyle.ThreeLevel)
return new KnxThreeLevelGroupAddress(groupAddress);
else if (style == KnxGroupAddressStyle.TwoLevel)
return new KnxTwoLevelGroupAddress(groupAddress);

return new KnxFreeStyleGroupAddress(groupAddress);
}

public bool Equals(int mainGroup, int middleGroup, int subGroup)
{
return (MainGroup == mainGroup && MiddleGroup == middleGroup && SubGroup == subGroup);
}

public bool Equals(int mainGroup, int subGroup)
{
return (MainGroup == mainGroup && MiddleGroup == 0 && SubGroup == subGroup);
}

public bool Equals(int subGroup)
{
return (MainGroup == 0 && MiddleGroup == 0 && SubGroup == subGroup);
}

public override bool Equals(object obj)
{
if (obj is KnxGroupAddress)
return base.Equals(obj);

return false;
}

public override int GetHashCode()
{
return base.GetHashCode();
}
}
}
Loading