added sunspec test server script
parent
0e3abab229
commit
6383b60ce3
|
|
@ -45,13 +45,16 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
|
|||
if (thing->thingClassId() == sunspecConnectionThingClassId) {
|
||||
|
||||
QHostAddress address = QHostAddress(info->thing()->paramValue(sunspecConnectionThingIpAddressParamTypeId).toString());
|
||||
int port = info->thing()->paramValue(sunspecConnectionThingPortParamTypeId).toInt();
|
||||
//int slaveId = info->thing()->paramValue(sunspecConnectionThingSlaveIdParamTypeId).toInt();
|
||||
|
||||
SunSpec *sunSpec;
|
||||
if (m_sunSpecConnections.contains(thing)) {
|
||||
qCDebug(dcSunSpec()) << "Reconfigure SunSpec connection with new address" << address;
|
||||
sunSpec = m_sunSpecConnections.value(thing);
|
||||
sunSpec->setHostAddress(address);
|
||||
} else {
|
||||
sunSpec = new SunSpec(address, 502, this);
|
||||
sunSpec = new SunSpec(address, port, this);
|
||||
m_sunSpecConnections.insert(info->thing(), sunSpec);
|
||||
}
|
||||
|
||||
|
|
@ -59,18 +62,24 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
|
|||
qCWarning(dcSunSpec()) << "Error connecting to SunSpec device";
|
||||
return info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
}
|
||||
connect(sunSpec, &SunSpec::connectionStateChanged, info, [info] (bool status) {
|
||||
qCDebug(dcSunSpec()) << "Modbus Inverter init finished" << status;
|
||||
if (status) {
|
||||
connect(sunSpec, &SunSpec::connectionStateChanged, info, [sunSpec, info] (bool status) {
|
||||
qCDebug(dcSunSpec()) << "Modbus connection init finished" << status;
|
||||
sunSpec->findBaseRegister();
|
||||
connect(sunSpec, &SunSpec::foundBaseRegister, info, [info] (uint modbusAddress) {
|
||||
qCDebug(dcSunSpec()) << "Found base register" << modbusAddress;
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
connect(info, &ThingSetupInfo::aborted, sunSpec, &SunSpec::deleteLater);
|
||||
connect(sunSpec, &SunSpec::destroyed, [this, info] {
|
||||
m_sunSpecConnections.remove(info->thing());
|
||||
});
|
||||
//connect(sunSpec, &SunSpecInverter::inverterDataReceived, this, &IntegrationPluginSunSpec::onInverterDataReceived);
|
||||
connect(sunSpec, &SunSpec::connectionStateChanged, this, [thing] (bool status) {
|
||||
thing->setStateValue(sunspecConnectionThingClassId, status);
|
||||
});
|
||||
connect(sunSpec, &SunSpec::mapHeaderReceived, this, &IntegrationPluginSunSpec::onMapHeaderReceived);
|
||||
connect(sunSpec, &SunSpec::mapReceived, this, &IntegrationPluginSunSpec::onMapReceived);
|
||||
|
||||
} else if (thing->thingClassId() == sunspecInverterThingClassId) {
|
||||
QHostAddress address = QHostAddress(info->thing()->paramValue(sunspecInverterThingIpAddressParamTypeId).toString());
|
||||
|
|
@ -145,7 +154,17 @@ void IntegrationPluginSunSpec::postSetupThing(Thing *thing)
|
|||
connect(m_refreshTimer, &PluginTimer::timeout, this, &IntegrationPluginSunSpec::onRefreshTimer);
|
||||
}
|
||||
|
||||
if (thing->thingClassId() == sunspecInverterThingClassId) {
|
||||
if (thing->thingClassId() == sunspecConnectionThingClassId) {
|
||||
SunSpec *connection = m_sunSpecConnections.take(thing);
|
||||
if (!connection)
|
||||
return;
|
||||
connection->readCommonMap();
|
||||
thing->setParamValue(sunspecConnectionManufacturerStateTypeId, connection->manufacturer());
|
||||
thing->setParamValue(sunspecInverterThingSerialNumberParamTypeId, connection->serialNumber());
|
||||
thing->setParamValue(sunspecInverterThingDeviceModelParamTypeId, connection->deviceModel());
|
||||
|
||||
|
||||
} else if (thing->thingClassId() == sunspecInverterThingClassId) {
|
||||
SunSpecInverter *sunSpecInverter = m_sunSpecInverters.take(thing);
|
||||
if (!sunSpecInverter)
|
||||
return;
|
||||
|
|
@ -304,6 +323,9 @@ void IntegrationPluginSunSpec::onRefreshTimer()
|
|||
{
|
||||
qCDebug(dcSunSpec()) << "On refresh timer";
|
||||
//get data
|
||||
foreach (SunSpec *connections, m_sunSpecConnections) {
|
||||
connections->readCommonMap();
|
||||
}
|
||||
foreach (SunSpecInverter *inverter, m_sunSpecInverters) {
|
||||
inverter->getInverterMap();
|
||||
}
|
||||
|
|
@ -338,6 +360,27 @@ void IntegrationPluginSunSpec::onConnectionStateChanged(bool status)
|
|||
qCDebug(dcSunSpec()) << "Connection state changed" << status;
|
||||
}
|
||||
|
||||
void IntegrationPluginSunSpec::onMapHeaderReceived(uint modbusAddress, SunSpec::BlockId mapId, uint mapLength)
|
||||
{
|
||||
qCDebug(dcSunSpec()) << "On map header received" << modbusAddress << mapId << mapLength;
|
||||
}
|
||||
|
||||
void IntegrationPluginSunSpec::onMapReceived(SunSpec::BlockId mapId, uint mapLength, QVector<quint16> data)
|
||||
{
|
||||
Q_UNUSED(data)
|
||||
SunSpec *connection = static_cast<SunSpec *>(sender());
|
||||
Thing *thing = m_sunSpecConnections.key(connection);
|
||||
if (!thing)
|
||||
return;
|
||||
|
||||
qCDebug(dcSunSpec()) << "On map received" << mapId << mapLength;
|
||||
if (mapId == SunSpec::BlockIdCommon && thing->thingClassId() == sunspecConnectionThingClassId) {
|
||||
thing->setStateValue(sunspecConnectionManufacturerStateTypeId, connection->manufacturer());
|
||||
thing->setStateValue(sunspecConnectionSerialNumberStateTypeId, connection->serialNumber());
|
||||
thing->setStateValue(sunspecConnectionDeviceModelStateTypeId, connection->deviceModel());
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginSunSpec::onWriteRequestExecuted(QUuid requestId, bool success)
|
||||
{
|
||||
qCDebug(dcSunSpec()) << "Write request executed" << requestId << success;
|
||||
|
|
|
|||
|
|
@ -73,6 +73,10 @@ private slots:
|
|||
void onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value);
|
||||
|
||||
void onConnectionStateChanged(bool status);
|
||||
|
||||
void onMapHeaderReceived(uint modbusAddress, SunSpec::BlockId mapId, uint mapLength);
|
||||
void onMapReceived(SunSpec::BlockId mapId, uint mapLength, QVector<quint16> data);
|
||||
|
||||
void onWriteRequestExecuted(QUuid requestId, bool success);
|
||||
void onWriteRequestError(QUuid requestId, const QString &error);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,23 @@
|
|||
"type": "int",
|
||||
"unit": "Seconds",
|
||||
"defaultValue": 15
|
||||
},
|
||||
{
|
||||
"id": "1a8895a0-c746-48af-9307-3a4636f24cc2",
|
||||
"name": "timeout",
|
||||
"displayName": "Timout",
|
||||
"type": "uint",
|
||||
"unit": "MilliSeconds",
|
||||
"defaultValue": 500
|
||||
},
|
||||
{
|
||||
"id": "9a4bfe01-315f-4ee7-98a9-f16b08ba12ad",
|
||||
"name": "numberOfRetries",
|
||||
"displayName": "Number of retries",
|
||||
"type": "uint",
|
||||
"defaultValue": 3,
|
||||
"minValue": 1,
|
||||
"maxValue": 10
|
||||
}
|
||||
],
|
||||
"vendors": [
|
||||
|
|
@ -32,28 +49,18 @@
|
|||
"type": "QString"
|
||||
},
|
||||
{
|
||||
"id": "04970315-ed3a-45ce-98fc-35ae3c4eb27b",
|
||||
"name":"manufacturer",
|
||||
"displayName": "Manufacturer",
|
||||
"type": "QString",
|
||||
"readOnly": true,
|
||||
"defaultValue": "Unkown"
|
||||
"id": "1fa4fc9c-f6be-47c7-928a-bcefc1142eec",
|
||||
"name":"port",
|
||||
"displayName": "Port",
|
||||
"type": "int",
|
||||
"defaultValue": 502
|
||||
},
|
||||
{
|
||||
"id": "58146c26-17d3-458e-a13f-d7f306c20c44",
|
||||
"name":"deviceModel",
|
||||
"displayName": "Device model",
|
||||
"type": "QString",
|
||||
"readOnly": true,
|
||||
"defaultValue": "Unkown"
|
||||
},
|
||||
{
|
||||
"id": "6ed498e1-37ca-4bb7-bac7-463509c7784e",
|
||||
"name":"serialNumber",
|
||||
"displayName": "Serial number",
|
||||
"type": "QString",
|
||||
"readOnly": true,
|
||||
"defaultValue": "Unkown"
|
||||
"id": "953064e0-4675-4538-a9a2-fa22ce2f347c",
|
||||
"name":"slaveId",
|
||||
"displayName": "Slave ID",
|
||||
"type": "int",
|
||||
"defaultValue": 1
|
||||
}
|
||||
],
|
||||
"stateTypes":[
|
||||
|
|
@ -65,6 +72,30 @@
|
|||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"cached": false
|
||||
},
|
||||
{
|
||||
"id": "04970315-ed3a-45ce-98fc-35ae3c4eb27b",
|
||||
"name":"manufacturer",
|
||||
"displayName": "Manufacturer",
|
||||
"displayNameEvent": "Manufacturer changed",
|
||||
"type": "QString",
|
||||
"defaultValue": "Unkown"
|
||||
},
|
||||
{
|
||||
"id": "58146c26-17d3-458e-a13f-d7f306c20c44",
|
||||
"name":"deviceModel",
|
||||
"displayName": "Device model",
|
||||
"displayNameEvent": "Device model changed",
|
||||
"type": "QString",
|
||||
"defaultValue": "Unkown"
|
||||
},
|
||||
{
|
||||
"id": "6ed498e1-37ca-4bb7-bac7-463509c7784e",
|
||||
"name":"serialNumber",
|
||||
"displayName": "Serial number",
|
||||
"displayNameEvent": "Serial number changed",
|
||||
"type": "QString",
|
||||
"defaultValue": "Unkown"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ SunSpec::~SunSpec()
|
|||
|
||||
bool SunSpec::connectModbus()
|
||||
{
|
||||
return m_modbusTcpClient->connectDevice();;
|
||||
return m_modbusTcpClient->connectDevice();
|
||||
}
|
||||
|
||||
void SunSpec::setHostAddress(const QHostAddress &hostAddress)
|
||||
|
|
@ -63,6 +63,27 @@ void SunSpec::setHostAddress(const QHostAddress &hostAddress)
|
|||
}
|
||||
}
|
||||
|
||||
void SunSpec::setPort(uint port)
|
||||
{
|
||||
m_port = port;
|
||||
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, port);
|
||||
}
|
||||
|
||||
void SunSpec::setSlaveId(uint slaveId)
|
||||
{
|
||||
m_slaveId = slaveId;
|
||||
}
|
||||
|
||||
void SunSpec::setTimeout(uint milliSeconds)
|
||||
{
|
||||
m_modbusTcpClient->setTimeout(milliSeconds);
|
||||
}
|
||||
|
||||
void SunSpec::setNumberOfRetries(uint retries)
|
||||
{
|
||||
m_modbusTcpClient->setNumberOfRetries(retries);
|
||||
}
|
||||
|
||||
QString SunSpec::manufacturer()
|
||||
{
|
||||
return m_manufacturer;
|
||||
|
|
@ -80,39 +101,43 @@ QString SunSpec::serialNumber()
|
|||
|
||||
void SunSpec::findBaseRegister()
|
||||
{
|
||||
qCDebug(dcSunSpec()) << "find base register";
|
||||
qCDebug(dcSunSpec()) << "Find base register";
|
||||
QList<int> validBaseRegisters;
|
||||
validBaseRegisters.append(0);
|
||||
validBaseRegisters.append(40000);
|
||||
validBaseRegisters.append(50000);
|
||||
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 40000, 2);
|
||||
Q_FOREACH (int baseRegister, validBaseRegisters) {
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, baseRegister, 2);
|
||||
if (QModbusReply *reply = m_modbusTcpClient->sendReadRequest(request, m_slaveId)) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
connect(reply, &QModbusReply::finished, this, [reply, this] {
|
||||
|
||||
if (QModbusReply *reply = m_modbusTcpClient->sendReadRequest(request, m_slaveId)) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
connect(reply, &QModbusReply::finished, this, [reply, this] {
|
||||
|
||||
if (reply->error() == QModbusDevice::NoError) {
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
//uint modbusAddress = unit.startAddress(); TODO
|
||||
if ((unit.value(0) << 16 | unit.value(1)) == 0x53756e53) {
|
||||
//Well-known value. Uniquely identifies this as a SunSpec Modbus Map
|
||||
qCDebug(dcSunSpec()) << "Found start of modbus map";
|
||||
//emit foundBaseRegister(modbusAddress);
|
||||
if (reply->error() == QModbusDevice::NoError) {
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
uint modbusAddress = unit.startAddress();
|
||||
if ((unit.value(0) << 16 | unit.value(1)) == 0x53756e53) {
|
||||
//Well-known value. Uniquely identifies this as a SunSpec Modbus Map
|
||||
qCDebug(dcSunSpec()) << "Found start of modbus map" << modbusAddress;
|
||||
m_baseRegister = modbusAddress;
|
||||
emit foundBaseRegister(modbusAddress);
|
||||
} else {
|
||||
qCWarning(dcSunSpec()) << "Got reply on base register, but value didn't mach 0x53756e53";
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcSunSpec()) << "Find base register read response error:" << reply->error();
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcSunSpec()) << "Read response error:" << reply->error();
|
||||
}
|
||||
});
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error) {
|
||||
qCWarning(dcSunSpec()) << "Modbus reply error:" << error;
|
||||
reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
});
|
||||
} else {
|
||||
qCWarning(dcSunSpec()) << "Find base register eead error: " << m_modbusTcpClient->errorString();
|
||||
delete reply; // broadcast replies return immediately
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcSunSpec()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||
delete reply; // broadcast replies return immediately
|
||||
qCWarning(dcSunSpec()) << "Find base register read error: " << m_modbusTcpClient->errorString();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcSunSpec()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -173,6 +173,11 @@ public:
|
|||
~SunSpec();
|
||||
bool connectModbus();
|
||||
void setHostAddress(const QHostAddress &hostAddress);
|
||||
void setPort(uint port);
|
||||
void setSlaveId(uint slaveId);
|
||||
void setTimeout(uint milliSeconds);
|
||||
void setNumberOfRetries(uint retries);
|
||||
|
||||
QString manufacturer();
|
||||
QString deviceModel();
|
||||
QString serialNumber();
|
||||
|
|
@ -207,6 +212,7 @@ signals:
|
|||
void connectionStateChanged(bool status);
|
||||
void requestExecuted(QUuid requetId, bool success);
|
||||
|
||||
void foundBaseRegister(int modbusAddress);
|
||||
void foundModbusMap(BlockId mapId, int modbusStartRegister);
|
||||
void modbusMapSearchFinished(const QList<BlockId> &mapIds, uint modbusStartRegister, const QString &error);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
if ! command -v suns &> /dev/null
|
||||
then
|
||||
echo "suns could not be found"
|
||||
echo "... installing"
|
||||
sudo apt update
|
||||
sudo apt install libmodbus-dev flex bison git
|
||||
|
||||
if [ ! -d "sunspec"]; then
|
||||
git clone https://github.com/Boernsman/sunspec.git
|
||||
fi
|
||||
cd ./sunspec/src
|
||||
make
|
||||
sudo make install
|
||||
fi
|
||||
|
||||
echo "Startin sunspec test server"
|
||||
sudo suns -s -vvvv -m models/test/composite_superdevice.model
|
||||
Loading…
Reference in New Issue