diff --git a/src/hoymiles/dtu.cpp b/src/hoymiles/dtu.cpp index a19fec1..af3df81 100644 --- a/src/hoymiles/dtu.cpp +++ b/src/hoymiles/dtu.cpp @@ -11,7 +11,8 @@ #include "portParameters.h" -Dtu::Dtu(const char *address, int id, bool rtu, bool tcp) { +Dtu::Dtu(const char *address, int id, bool rtu, bool tcp) : dtuPort(0) { + dtuPort.statusPortStartAddress = 0xd000; if (tcp) { this->modbus = modbus_new_tcp(address, id); } @@ -22,7 +23,7 @@ Dtu::Dtu(const char *address, int id, bool rtu, bool tcp) { this->connected = false; if (modbus_connect(this->modbus) == -1) { - std::cerr << "NOT CONNECTED" << std::endl; + std::cerr << "[" << id << "] NOT_CONNECTED" << std::endl; } else { this->connected = true; if (rtu) { @@ -32,6 +33,24 @@ Dtu::Dtu(const char *address, int id, bool rtu, bool tcp) { } } +Dtu::Dtu(modbus_t *modbus, int id = -1) : dtuPort(0) { + dtuPort.statusPortStartAddress = 0xd000; + + this->modbus = modbus; + this->rtuId = id; + + this->connected = false; + if (modbus_connect(this->modbus) == -1) { + std::cerr << "[" << id << "] NOT_CONNECTED" << std::endl; + } else { + this->connected = true; + if (id != -1) { + modbus_set_slave(this->modbus, rtuId); + } + this->populateMicroinverters(); + } +} + bool Dtu::isConnected() { return this->connected; } Dtu::~Dtu() { @@ -40,14 +59,32 @@ Dtu::~Dtu() { } void Dtu::populateMicroinverters() { + if(this->rtuId != -1) { + modbus_set_slave(this->modbus, this->rtuId); + } + int portStartAddress = 0x4000; - uint16_t registers[19]; + int registersToRead{19}; + uint16_t registers[registersToRead]; + + bool lastSuccesful{true}; + + int addressToSkip{-1}; while (portStartAddress <= (0x4000 + (0x0019 * 99))) { - int registerCount; - registerCount = modbus_read_registers(this->modbus, portStartAddress, 19, registers); + int registerCount{-1}; + int timesTried{0}; + while (((timesTried < 3) && (lastSuccesful && registerCount == -1) && portStartAddress != addressToSkip)) { + registerCount = modbus_read_registers(this->modbus, portStartAddress, registersToRead, registers); + timesTried++; + } portStartAddress += 0x0019; - if (registers[0] == 12) { + if ((registers[0] == 12 && registerCount != -1) && portStartAddress != addressToSkip) { + if (!lastSuccesful) { + addressToSkip = portStartAddress; + portStartAddress -= 2 * 0x0019; + } + lastSuccesful = true; Port port{portStartAddress}; port.setParametersFromMicroinverterArray(registers, 0); @@ -56,10 +93,23 @@ void Dtu::populateMicroinverters() { this->microinverters.push_back(microinverter); } - this->getMicroinverterBySerialNumber(port.getParameterByName("microinverterSerialNumber").first.get()->getValue().first.i).first->ports.push_back(port); + Microinverter *microinverter = this->getMicroinverterBySerialNumber(port.getParameterByName("microinverterSerialNumber").first.get()->getValue().first.i).first; + std::vector::iterator portsIterator = microinverter->ports.begin(); + bool valueExists{false}; + while (portsIterator != microinverter->ports.end() && !valueExists) { + if (portsIterator->getParameterByName("portNumber").first.get()->getValue().first.i == port.getParameterByName("portNumber").first.get()->getValue().first.i) { + valueExists = true; + } + portsIterator++; + } + if (!valueExists) { + microinverter->ports.push_back(port); + } + } else { + lastSuccesful = false; } - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + std::this_thread::sleep_for(std::chrono::milliseconds(20)); } } @@ -76,6 +126,9 @@ std::pair Dtu::getMicroinverterBySerialNumber(long long s } void Dtu::updateMicroinverters(std::vector ¶metersToGet, bool allParameters, std::vector µinvertersToGet) { + if(this->rtuId != -1) { + modbus_set_slave(this->modbus, this->rtuId); + } if (microinvertersToGet.empty()) { std::vector::iterator microinvertersIterator = this->microinverters.begin(); while (microinvertersIterator != this->microinverters.end()) { @@ -155,4 +208,39 @@ void Dtu::listOfMicroinverters() { std::cout << " " << microinvertersIterator->serialNumber << std::endl; microinvertersIterator++; } -} \ No newline at end of file +} + +float Dtu::getCurrentPower() { + std::vector::iterator microinvertersIterator = this->microinverters.begin(); + float currentPower{0}; + while (microinvertersIterator != this->microinverters.end()) { + currentPower += microinvertersIterator->getCurrentPower(); + microinvertersIterator++; + } + return currentPower; +} + +int Dtu::getCurrentOnOff() { + if(this->microinverters.size() == 0) { + return 0; + } + std::vector::iterator microinvertersIterator = this->microinverters.begin(); + int currentOn{0}; + while(microinvertersIterator != this->microinverters.end()) { + currentOn += microinvertersIterator->getCurrentOnOff(); + microinvertersIterator++; + } + float balance = currentOn / this->microinverters.size(); + if(balance >= 0.5) { + return 1; + } + else { + return 0; + } +} + +void Dtu::turnOffMicroinverters() { this->dtuPort.getStatusByName("onOff").first.get()->writeValue(0, this->modbus, this->dtuPort.statusPortStartAddress); } + +void Dtu::turnOnMicroinverters() { this->dtuPort.getStatusByName("onOff").first.get()->writeValue(1, this->modbus, this->dtuPort.statusPortStartAddress); } + +void Dtu::limitMicroinverters(uint16_t limit) { this->dtuPort.getStatusByName("limitActivePower").first.get()->writeValue(limit, this->modbus, this->dtuPort.statusPortStartAddress); } \ No newline at end of file diff --git a/src/hoymiles/microinverter.cpp b/src/hoymiles/microinverter.cpp index a6542a2..be7ef10 100644 --- a/src/hoymiles/microinverter.cpp +++ b/src/hoymiles/microinverter.cpp @@ -8,7 +8,7 @@ #include "port.h" #include "sunspec.h" -Microinverter::Microinverter(modbus_t *modbus, int startAddress, long long serialNumber) : sunspec(40000, modbus) { +Microinverter::Microinverter(modbus_t *modbus, int startAddress, long long serialNumber) { this->modbus = modbus; this->startAddress = startAddress; this->serialNumber = serialNumber; @@ -136,4 +136,30 @@ void Microinverter::setStatusWholeMicroinverter(uint16_t value, std::string stat this->ports.begin()->getStatusByName(statusName).first.get()->writeValue(value, this->modbus, this->ports.begin()->statusPortStartAddress); } } +} + +float Microinverter::getCurrentPower() { + std::vector::iterator portsIterator = this->ports.begin(); + float currentPower{0}; + while(portsIterator != this->ports.end()) { + currentPower += portsIterator->getParameterByName("pvPower").first.get()->getValue().first.f; + portsIterator++; + } + return currentPower; +} + +int Microinverter::getCurrentOnOff() { + std::vector::iterator portsIterator = this->ports.begin(); + int currentOn{0}; + while(portsIterator != this->ports.end()) { + currentOn += portsIterator->getStatusByName("onOff").first.get()->getValue().first.i; + portsIterator++; + } + float balance = currentOn / this->ports.size(); + if(balance >= 0.5) { + return 1; + } + else { + return 0; + } } \ No newline at end of file diff --git a/src/hoymiles/sunspec.cpp b/src/hoymiles/sunspec.cpp index 3ad2f64..b475c6d 100644 --- a/src/hoymiles/sunspec.cpp +++ b/src/hoymiles/sunspec.cpp @@ -16,10 +16,10 @@ Sunspec::Sunspec(int address, modbus_t *modbus) { } void Sunspec::setValues() { - uint16_t registers[70]; + uint16_t registers[2]; int registerCount; - registerCount = modbus_read_registers(this->modbus, this->sunspecAddress, 70, registers); + registerCount = modbus_read_registers(this->modbus, this->sunspecAddress, 2, registers); std::vector>::iterator parametersIterator = this->parameters.begin(); while(parametersIterator != this->parameters.end()) { diff --git a/src/hoymiles/sunspecParameters/sunspecParametersGeneric.cpp b/src/hoymiles/sunspecParameters/sunspecParametersGeneric.cpp index 93186e5..81dd916 100644 --- a/src/hoymiles/sunspecParameters/sunspecParametersGeneric.cpp +++ b/src/hoymiles/sunspecParameters/sunspecParametersGeneric.cpp @@ -10,7 +10,9 @@ SunspecParameter::SunspecParameter(std::string name, int registerAddressOffset, void SunspecParameter::getValueFromRegisters(uint16_t *registers, int addressOffset) {} -std::pair SunspecParameter::getValue() {} +std::pair SunspecParameter::getValue() { + return {this->value, this->valueType}; +} SunspecParameterString32::SunspecParameterString32(std::string name, int registerAddressOffset, int registerSize) : SunspecParameter(name, registerAddressOffset, registerSize) {}