Kamstrup parsing working

This commit is contained in:
Roar Fredriksen
2017-10-24 22:01:41 +02:00
parent d144e293e2
commit d1c2ca7093
25 changed files with 466 additions and 259 deletions

View File

@@ -19,15 +19,15 @@
</ItemGroup>
<ItemGroup>
<!-- <ClInclude Include="$(MSBuildThisFileDirectory)HanReader.h" /> -->
<ClInclude Include="$(MSBuildThisFileDirectory)..\KamstrupTest\Kamstrup.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)src\Crc16.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)src\DlmsReader.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)src\HanReader.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)src\KaifaHan.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)src\Kaifa.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)src\Crc16.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)src\DlmsReader.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)src\HanReader.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)src\KaifaHan.cpp" />
</ItemGroup>
</Project>

View File

@@ -20,9 +20,6 @@
<ClCompile Include="C:\Users\roarf\OneDrive\Documents\GitHub\AmsToMqttBridge\Code\Arduino\HanReader\src\HanReader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="C:\Users\roarf\OneDrive\Documents\GitHub\AmsToMqttBridge\Code\Arduino\HanReader\src\KaifaHan.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="$(MSBuildThisFileDirectory)readme.txt" />
@@ -38,7 +35,10 @@
<ClInclude Include="C:\Users\roarf\OneDrive\Documents\GitHub\AmsToMqttBridge\Code\Arduino\HanReader\src\HanReader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="C:\Users\roarf\OneDrive\Documents\GitHub\AmsToMqttBridge\Code\Arduino\HanReader\src\KaifaHan.h">
<ClInclude Include="C:\Users\roarf\OneDrive\Documents\GitHub\AmsToMqttBridge\Code\Arduino\HanReader\..\KamstrupTest\Kamstrup.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="C:\Users\roarf\OneDrive\Documents\GitHub\AmsToMqttBridge\Code\Arduino\HanReader\src\Kaifa.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>

View File

@@ -8,11 +8,14 @@ HanReader::HanReader()
void HanReader::setup(HardwareSerial *hanPort, unsigned long baudrate, SerialConfig config, Stream *debugPort)
{
// Initialize H/W serial port for MBus communication
hanPort->begin(baudrate, config);
while (!hanPort) {}
bytesRead = 0;
if (hanPort != NULL)
{
hanPort->begin(baudrate, config);
while (!hanPort) {}
}
han = hanPort;
bytesRead = 0;
debug = debugPort;
if (debug) debug->println("MBUS serial setup complete");
}
@@ -27,44 +30,174 @@ void HanReader::setup(HardwareSerial *hanPort, Stream *debugPort)
setup(hanPort, 2400, SERIAL_8E1, debugPort);
}
bool HanReader::read()
bool HanReader::read(byte data)
{
if (han->available())
{
byte newByte = han->read();
if (reader.Read(newByte))
{
bytesRead = reader.GetRawData(buffer, 0, 512);
list = (List)kaifa.GetListID(buffer, 0, bytesRead);
return true;
}
}
return false;
if (reader.Read(data))
{
bytesRead = reader.GetRawData(buffer, 0, 512);
list = getInt(1, buffer, 0, bytesRead);
return true;
}
}
List HanReader::getList()
bool HanReader::read()
{
if (han->available())
{
byte newByte = han->read();
return read(newByte);
}
return false;
}
int HanReader::getList()
{
return list;
}
time_t HanReader::getPackageTime()
{
return kaifa.GetPackageTime(buffer, 0, bytesRead);
return getTime(0);
}
time_t HanReader::getTime(int objectId)
{
return getTime(objectId, buffer, 0, bytesRead);
}
int HanReader::getInt(List1_ObisObjects objectId) { return getInt((int)objectId); }
int HanReader::getInt(List2_ObisObjects objectId) { return getInt((int)objectId); }
int HanReader::getInt(List3_ObisObjects objectId) { return getInt((int)objectId); }
int HanReader::getInt(int objectId)
{
return kaifa.GetInt(objectId, buffer, 0, bytesRead);
return getInt(objectId, buffer, 0, bytesRead);
}
String HanReader::getString(List1_ObisObjects objectId) { return getString((int)objectId); }
String HanReader::getString(List2_ObisObjects objectId) { return getString((int)objectId); }
String HanReader::getString(List3_ObisObjects objectId) { return getString((int)objectId); }
String HanReader::getString(int objectId)
{
return kaifa.GetString(objectId, buffer, 0, bytesRead);
return getString(objectId, buffer, 0, bytesRead);
}
int HanReader::findValuePosition(int dataPosition, byte *buffer, int start, int length)
{
for (int i = start + dataHeader; i<length; i++)
{
if (dataPosition-- == 0)
return i;
else if (buffer[i] == 0x0A) // OBIS code value
i += buffer[i + 1] + 1;
else if (buffer[i] == 0x09) // string value
i += buffer[i + 1] + 1;
else if (buffer[i] == 0x02) // byte value (1 byte)
i += 1;
else if (buffer[i] == 0x12) // integer value (2 bytes)
i += 2;
else if (buffer[i] == 0x06) // integer value (4 bytes)
i += 4;
else
{
if (debug)
{
debug->print("Unknown data type found: 0x");
debug->println(buffer[i], HEX);
}
return 0; // unknown data type found
}
}
if (debug)
{
debug->print("Passed the end of the data. Length was: ");
debug->println(length);
}
return 0;
}
time_t HanReader::getTime(int dataPosition, byte *buffer, int start, int length)
{
int timeStart = findValuePosition(dataPosition, buffer, start, length);
int year = buffer[start + timeStart] << 8 |
buffer[start + timeStart + 1];
int month = buffer[start + timeStart + 2];
int day = buffer[start + timeStart + 3];
int hour = buffer[start + timeStart + 5];
int minute = buffer[start + timeStart + 6];
int second = buffer[start + timeStart + 7];
return toUnixTime(year, month, day, hour, minute, second);
}
int HanReader::getInt(int dataPosition, byte *buffer, int start, int length)
{
int valuePosition = findValuePosition(dataPosition, buffer, start, length);
if (valuePosition > 0)
{
int value = 0;
int bytes = 0;
switch (buffer[valuePosition++])
{
case 0x12:
bytes = 2;
break;
case 0x06:
bytes = 4;
break;
case 0x02:
bytes = 1;
break;
}
for (int i = valuePosition; i < valuePosition + bytes; i++)
{
value = value << 8 | buffer[i];
}
debug->println(value);
return value;
}
return 0;
}
String HanReader::getString(int dataPosition, byte *buffer, int start, int length)
{
int valuePosition = findValuePosition(dataPosition, buffer, start, length);
if (valuePosition > 0)
{
String value = String("");
for (int i = valuePosition + 2; i < valuePosition + buffer[valuePosition + 1]; i++)
{
value += String((char)buffer[i]);
}
return value;
}
return String("");
}
time_t HanReader::toUnixTime(int year, int month, int day, int hour, int minute, int second)
{
byte daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
long secondsPerMinute = 60;
long secondsPerHour = secondsPerMinute * 60;
long secondsPerDay = secondsPerHour * 24;
long time = (year - 1970) * secondsPerDay * 365L;
for (int yearCounter = 1970; yearCounter<year; yearCounter++)
if ((yearCounter % 4 == 0) && ((yearCounter % 100 != 0) || (yearCounter % 400 == 0)))
time += secondsPerDay;
if (month > 2 && (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)))
time += secondsPerDay;
for (int monthCounter = 1; monthCounter<month; monthCounter++)
time += daysInMonth[monthCounter - 1] * secondsPerDay;
time += (day - 1) * secondsPerDay;
time += hour * secondsPerHour;
time += minute * secondsPerMinute;
time += second;
return (time_t)time;
}

View File

@@ -8,37 +8,41 @@
#endif
#include "KaifaHan.h"
#include "DlmsReader.h"
class HanReader
{
public:
HanReader();
void setup(HardwareSerial *hanPort);
void setup(HardwareSerial *hanPort, Stream *debugPort);
void setup(HardwareSerial *hanPort, unsigned long baudrate, SerialConfig config, Stream *debugPort);
bool read();
List getList();
time_t getPackageTime();
int getInt(List1_ObisObjects objectId);
int getInt(List2_ObisObjects objectId);
int getInt(List3_ObisObjects objectId);
int getInt(int objectId);
String getString(List1_ObisObjects objectId);
String getString(List2_ObisObjects objectId);
String getString(List3_ObisObjects objectId);
String getString(int objectId);
public:
const uint dataHeader = 8;
private:
Stream *debug;
HardwareSerial *han;
byte buffer[512];
int bytesRead;
KaifaHan kaifa;
DlmsReader reader;
List list;
HanReader();
void setup(HardwareSerial *hanPort);
void setup(HardwareSerial *hanPort, Stream *debugPort);
void setup(HardwareSerial *hanPort, unsigned long baudrate, SerialConfig config, Stream *debugPort);
bool read();
bool read(byte data);
int getList();
time_t getPackageTime();
int getInt(int objectId);
String getString(int objectId);
time_t getTime(int objectId);
private:
Stream *debug;
HardwareSerial *han;
byte buffer[512];
int bytesRead;
DlmsReader reader;
int list;
int findValuePosition(int dataPosition, byte *buffer, int start, int length);
long getTime(int dataPosition, byte *buffer, int start, int length);
int getInt(int dataPosition, byte *buffer, int start, int length);
String getString(int dataPosition, byte *buffer, int start, int length);
time_t toUnixTime(int year, int month, int day, int hour, int minute, int second);
};

View File

@@ -0,0 +1,55 @@
#ifndef _KAIFA_h
#define _KAIFA_h
enum class Kaifa : byte {
List1 = 0x01,
List2 = 0x0D,
List3 = 0x12
};
enum class Kaifa_List1_ObisObjects {
ActivePowerImported
};
enum class Kaifa_List2_ObisObjects {
Time,
ListID,
ObisListVersionIdentifier,
MeterID,
MeterType,
ActivePowerImported,
ActivePowerExported,
ReactivePowerImported,
ReactivePowerExported,
CurrentPhaseL1,
CurrentPhaseL2,
CurrentPhaseL3,
VoltagePhaseL1,
VoltagePhaseL2,
VoltagePhaseL3
};
enum class Kaifa_List3_ObisObjects {
Time,
ListID,
ObisListVersionIdentifier,
MeterID,
MeterType,
ActivePowerImported,
ActivePowerExported,
ReactivePowerImported,
ReactivePowerExported,
CurrentPhaseL1,
CurrentPhaseL2,
CurrentPhaseL3,
VoltagePhaseL1,
VoltagePhaseL2,
VoltagePhaseL3,
ClockAndDate,
TotalActiveEnergyImported,
TotalActiveEnergyExported,
TotalReactiveEnergyImported,
TotalReactiveEnergyExported
};
#endif

View File

@@ -1,104 +0,0 @@
#include "KaifaHan.h"
byte KaifaHan::GetListID(byte *buffer, int start, int length)
{
if (length > 23)
{
byte list = buffer[start + 23];
if (list == (byte)List::List1) return (byte)List::List1;
if (list == (byte)List::List2) return (byte)List::List2;
if (list == (byte)List::List3) return (byte)List::List3;
}
return (byte)List::ListUnknown;
}
long KaifaHan::GetPackageTime(byte *buffer, int start, int length)
{
const int timeStart = 10;
int year = buffer[start + timeStart] << 8 |
buffer[start + timeStart + 1];
int month = buffer[start + timeStart + 2];
int day = buffer[start + timeStart + 3];
int hour = buffer[start + timeStart + 5];
int minute = buffer[start + timeStart + 6];
int second = buffer[start + timeStart + 7];
return toUnixTime(year, month, day, hour, minute, second);
}
int KaifaHan::GetInt(int dataPosition, byte *buffer, int start, int length)
{
int valuePosition = findValuePosition(dataPosition, buffer, start, length);
if (valuePosition > 0)
{
int value = 0;
for (int i = valuePosition + 1; i < valuePosition + 5; i++)
{
value = value << 8 | buffer[i];
}
return value;
}
return 0;
}
int KaifaHan::findValuePosition(int dataPosition, byte *buffer, int start, int length)
{
const int dataStart = 24;
for (int i=start + dataStart; i<length; i++)
{
if (dataPosition-- == 0)
return i;
else if (buffer[i] == 0x09) // string value
i += buffer[i+1] + 1;
else if (buffer[i] == 0x06) // integer value
i += 4;
else
return 0; // unknown data type found
}
return 0;
}
String KaifaHan::GetString(int dataPosition, byte *buffer, int start, int length)
{
int valuePosition = findValuePosition(dataPosition, buffer, start, length);
if (valuePosition > 0)
{
String value = String("");
for (int i = valuePosition + 2; i < valuePosition + buffer[valuePosition + 1]; i++)
{
value += String((char)buffer[i]);
}
return value;
}
return String("");
}
time_t KaifaHan::toUnixTime(int year, int month, int day, int hour, int minute, int second)
{
byte daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
long secondsPerMinute = 60;
long secondsPerHour = secondsPerMinute * 60;
long secondsPerDay = secondsPerHour * 24;
long time = (year - 1970) * secondsPerDay * 365L;
for (int yearCounter = 1970; yearCounter<year; yearCounter++)
if ((yearCounter % 4 == 0) && ((yearCounter % 100 != 0) || (yearCounter % 400 == 0)))
time += secondsPerDay;
if (month > 2 && (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)))
time += secondsPerDay;
for (int monthCounter = 1; monthCounter<month; monthCounter++)
time += daysInMonth[monthCounter - 1] * secondsPerDay;
time += (day - 1) * secondsPerDay;
time += hour * secondsPerHour;
time += minute * secondsPerMinute;
time += second;
return (time_t)time;
}

View File

@@ -1,73 +0,0 @@
#ifndef _KAIFAHAN_h
#define _KAIFAHAN_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
class KaifaHan
{
public:
byte GetListID(byte *buffer, int start, int length);
long GetPackageTime(byte *buffer, int start, int length);
int GetInt(int dataPosition, byte *buffer, int start, int length);
String GetString(int dataPosition, byte *buffer, int start, int length);
protected:
private:
int findValuePosition(int dataPosition, byte *buffer, int start, int length);
time_t toUnixTime(int year, int month, int day, int hour, int minute, int second);
};
enum class List : byte {
ListUnknown = 0x00,
List1 = 0x01,
List2 = 0x0D,
List3 = 0x12
};
enum class List1_ObisObjects {
ActivePowerImported
};
enum class List2_ObisObjects {
ObisListVersionIdentifier,
MeterID,
MeterType,
ActivePowerImported,
ActivePowerExported,
ReactivePowerImported,
ReactivePowerExported,
CurrentPhaseL1,
CurrentPhaseL2,
CurrentPhaseL3,
VoltagePhaseL1,
VoltagePhaseL2,
VoltagePhaseL3
};
enum class List3_ObisObjects {
ObisListVersionIdentifier,
MeterID,
MeterType,
ActivePowerImported,
ActivePowerExported,
ReactivePowerImported,
ReactivePowerExported,
CurrentPhaseL1,
CurrentPhaseL2,
CurrentPhaseL3,
VoltagePhaseL1,
VoltagePhaseL2,
VoltagePhaseL3,
ClockAndDate,
TotalActiveEnergyImported,
TotalActiveEnergyExported,
TotalReactiveEnergyImported,
TotalReactiveEnergyExported
};
#endif

View File

@@ -0,0 +1,45 @@
// Kamstrup.h
#ifndef _KAMSTRUP_h
#define _KAMSTRUP_h
enum class Kamstrup
{
List1 = 0x19
};
enum class Kamstrup_List1
{
Kamstrup_List1_Time,
Kamstrup_List1_ListID,
Kamstrup_List1_ListVersionIdentifier,
Kamstrup_List1_MeterID_OBIS,
Kamstrup_List1_MeterID,
Kamstrup_List1_MeterType_OBIS,
Kamstrup_List1_MeterType,
Kamstrup_List1_ActivePowerPos_OBIS,
Kamstrup_List1_ActivePowerPos,
Kamstrup_List1_ActivePowerNeg_OBIS,
Kamstrup_List1_ActivePowerNeg,
Kamstrup_List1_ReactivePowerPos_OBIS,
Kamstrup_List1_ReactivePowerPos,
Kamstrup_List1_ReactivePowerNeg_OBIS,
Kamstrup_List1_ReactivePowerNeg,
Kamstrup_List1_CurrentL1_OBIS,
Kamstrup_List1_CurrentL1,
Kamstrup_List1_CurrentL2_OBIS,
Kamstrup_List1_CurrentL2,
Kamstrup_List1_CurrentL3_OBIS,
Kamstrup_List1_CurrentL3,
Kamstrup_List1_VoltageL1_OBIS,
Kamstrup_List1_VoltageL1,
Kamstrup_List1_VoltageL2_OBIS,
Kamstrup_List1_VoltageL2,
Kamstrup_List1_VoltageL3_OBIS,
Kamstrup_List1_VoltageL3
};
#endif