diff --git a/inc/hoymiles/dtu.h b/inc/hoymiles/dtu.h index b4a3ccd..bf11234 100644 --- a/inc/hoymiles/dtu.h +++ b/inc/hoymiles/dtu.h @@ -16,11 +16,11 @@ class Dtu { void populateMicroinverters(); - std::pair getMicroinverterBySerialNumber(long long serialNumber); - public: Dtu(const char *ip_address, int port); + std::pair getMicroinverterBySerialNumber(long long serialNumber); + bool isConnected(); bool modbusError(); @@ -31,6 +31,10 @@ class Dtu { void printMicroinverters(std::vector ¶metersToGet, bool allParameters, std::vector µinvertersToGet, bool shortNames, bool printTodayProduction, bool printTotalProduction); + void setStatusMicroinverters(uint16_t value, std::string statusName, std::vector& microinvertersToSet); + + bool empty(); + ~Dtu(); }; diff --git a/inc/hoymiles/microinverter.h b/inc/hoymiles/microinverter.h index 5e817cb..26623aa 100644 --- a/inc/hoymiles/microinverter.h +++ b/inc/hoymiles/microinverter.h @@ -17,6 +17,8 @@ class Microinverter { int startAddress; + int statusStartAddress; + public: Microinverter(std::shared_ptr modbus, int startAddress, long long serialNumber); @@ -30,11 +32,17 @@ class Microinverter { void updateParameters(std::vector ¶metersToGet, bool allParameters); + void updateStatusParameters(); + void printPorts(std::vector ¶metersToGet, bool allParameters, bool shortNames); long long getTodayProduction(); long long getTotalProduction(); + + void setStatus(std::vector> portsToSet, std::string statusName); + + void setStatusWholeMicroinverter(uint16_t value, std::string statusName); }; #endif \ No newline at end of file diff --git a/inc/hoymiles/port.h b/inc/hoymiles/port.h index 6cb1d62..df37dd5 100644 --- a/inc/hoymiles/port.h +++ b/inc/hoymiles/port.h @@ -6,6 +6,7 @@ #include #include "portParametersGeneric.h" +#include "portParameters.h" #include "modbus.h" class Port { @@ -22,15 +23,27 @@ class Port { int portStartAddress; + int statusPortStartAddress; + std::vector> parameters; + std::vector> statusParameters; + std::pair, bool> getParameterByName(std::string name); + std::pair, bool> getStatusByName(std::string name); + // void updateParameters(std::vector ¶metersToGet, bool allParameters); void setParametersFromMicroinverterArray(uint16_t *registers, int addressOffset); + void setStatusesFromMicroinverterArray(uint16_t *registers, int addressOffset); + void printParameters(std::vector ¶metersToGet, bool allParameters, bool shortNames); + + void turnOff(class modbus &modbus); + + bool isOff(class modbus &modbus); }; #endif \ No newline at end of file diff --git a/inc/hoymiles/portParameters/portParameters.h b/inc/hoymiles/portParameters/portParameters.h index 93d1a8b..cd15028 100644 --- a/inc/hoymiles/portParameters/portParameters.h +++ b/inc/hoymiles/portParameters/portParameters.h @@ -5,7 +5,7 @@ class PortParameterMicroinverterSerialNumber : public PortParameterInt { private: - void setValueFromRegisters(uint16_t *registers, int addressOffset); + void getValueFromRegisters(uint16_t *registers, int addressOffset); public: PortParameterMicroinverterSerialNumber(); @@ -81,4 +81,14 @@ class PortParameterLinkStatus : public PortParameterInt { PortParameterLinkStatus(); }; +class PortParameterOnOff : public PortParameterInt { + public: + PortParameterOnOff(); +}; + +class PortParameterLimitActivePower : public PortParameterInt { + public: + PortParameterLimitActivePower(); +}; + #endif \ No newline at end of file diff --git a/inc/hoymiles/portParameters/portParametersGeneric.h b/inc/hoymiles/portParameters/portParametersGeneric.h index b91952b..23f3856 100644 --- a/inc/hoymiles/portParameters/portParametersGeneric.h +++ b/inc/hoymiles/portParameters/portParametersGeneric.h @@ -15,8 +15,11 @@ class PortParameter { std::string unit; + bool r; + bool w; + public: - PortParameter(std::string name, std::string shortName, std::string unit, uint16_t parameterAddressOffset, int registerSize); + PortParameter(std::string name, std::string shortName, std::string unit, bool r, bool w, uint16_t parameterAddressOffset, int registerSize); virtual ~PortParameter(); @@ -39,9 +42,11 @@ class PortParameter { std::pair getValue(); + PortParameter& writeValue(uint16_t value, class modbus& modbus, int portStartAddress); + virtual std::string getOutputValue(); - virtual void setValueFromRegisters(uint16_t *registers, int addressOffset); + virtual void getValueFromRegisters(uint16_t *registers, int addressOffset); // void updateValue(std::shared_ptr modubs, uint16_t portStartAddress); }; @@ -51,22 +56,22 @@ class PortParameterFloat : public PortParameter { int decimalPlaces; public: - PortParameterFloat(std::string name, std::string shortName, std::string unit, int decimalPlaces, uint16_t parameterAddressOffset, int registerSize); + PortParameterFloat(std::string name, std::string shortName, std::string unit, bool r, bool w, int decimalPlaces, uint16_t parameterAddressOffset, int registerSize); std::string getOutputValue(); - virtual void setValueFromRegisters(uint16_t *registers, int addressOffset); + virtual void getValueFromRegisters(uint16_t *registers, int addressOffset); }; class PortParameterInt : public PortParameter { protected: public: - PortParameterInt(std::string name, std::string shortName, std::string unit, uint16_t parameterAddressOffset, int registerSize); + PortParameterInt(std::string name, std::string shortName, std::string unit, bool r, bool w, uint16_t parameterAddressOffset, int registerSize); std::string getOutputValue(); - virtual void setValueFromRegisters(uint16_t *registers, int addressOffset); + virtual void getValueFromRegisters(uint16_t *registers, int addressOffset); }; #endif \ No newline at end of file diff --git a/inc/hoymiles/sunspecParameters/sunspecParameters.h b/inc/hoymiles/sunspecParameters/sunspecParameters.h index 745d47c..cdf4bed 100644 --- a/inc/hoymiles/sunspecParameters/sunspecParameters.h +++ b/inc/hoymiles/sunspecParameters/sunspecParameters.h @@ -9,7 +9,7 @@ class SunspecParameterManufacturer : public SunspecParameterString32 { public: SunspecParameterManufacturer(); - void setValueFromRegisters(uint16_t *registers, int addressOffset); + void getValueFromRegisters(uint16_t *registers, int addressOffset); }; #endif \ No newline at end of file diff --git a/inc/hoymiles/sunspecParameters/sunspecParametersGeneric.h b/inc/hoymiles/sunspecParameters/sunspecParametersGeneric.h index ab916a6..aba5e8d 100644 --- a/inc/hoymiles/sunspecParameters/sunspecParametersGeneric.h +++ b/inc/hoymiles/sunspecParameters/sunspecParametersGeneric.h @@ -33,7 +33,7 @@ class SunspecParameter { public: - virtual void setValueFromRegisters(uint16_t *registers, int addressOffset); + virtual void getValueFromRegisters(uint16_t *registers, int addressOffset); std::pair getValue(); }; @@ -44,7 +44,7 @@ class SunspecParameter { // public: // SunspecParameterUint32(std::string name, int registerAddressOffset, int registerSize); -// virtual void setValueFromRegisters(uint16_t *registers, int addressOffset); +// virtual void getValueFromRegisters(uint16_t *registers, int addressOffset); // }; // class SunspecParameterUint16 : public SunspecParameter { @@ -53,7 +53,7 @@ class SunspecParameter { // public: // SunspecParameterUint16(std::string name, int registerAddressOffset, int registerSize); -// virtual void setValueFromRegisters(uint16_t *registers, int addressOffset); +// virtual void getValueFromRegisters(uint16_t *registers, int addressOffset); // }; class SunspecParameterString32 : public SunspecParameter { @@ -63,7 +63,7 @@ class SunspecParameterString32 : public SunspecParameter { public: SunspecParameterString32(std::string name, int registerAddressOffset, int registerSize); - virtual void setValueFromRegisters(uint16_t *registers, int addressOffset); + virtual void getValueFromRegisters(uint16_t *registers, int addressOffset); }; // class SunspecParameterString16 : public SunspecParameter { @@ -73,7 +73,7 @@ class SunspecParameterString32 : public SunspecParameter { // public: // SunspecParameterString16(std::string name, int registerAddressOffset, int registerSize); -// virtual void setValueFromRegisters(uint16_t *registers, int addressOffset); +// virtual void getValueFromRegisters(uint16_t *registers, int addressOffset); // }; // class SunspecParameterSunssf : public SunspecParameter { @@ -82,7 +82,7 @@ class SunspecParameterString32 : public SunspecParameter { // public: // SunspecParameterSunssf(std::string name, int registerAddressOffset, int registerSize); -// virtual void setValueFromRegisters(uint16_t *registers, int addressOffset); +// virtual void getValueFromRegisters(uint16_t *registers, int addressOffset); // }; // class SunspecParameterInt16 : public SunspecParameter { @@ -91,7 +91,7 @@ class SunspecParameterString32 : public SunspecParameter { // public: // SunspecParameterInt16(std::string name, int registerAddressOffset, int registerSize); -// virtual void setValueFromRegisters(uint16_t *registers, int addressOffset); +// virtual void getValueFromRegisters(uint16_t *registers, int addressOffset); // }; // class SunspecParameterAcc32 : public SunspecParameter { @@ -100,7 +100,7 @@ class SunspecParameterString32 : public SunspecParameter { // public: // SunspecParameterAcc32(std::string name, int registerAddressOffset, int registerSize); -// virtual void setValueFromRegisters(uint16_t *registers, int addressOffset); +// virtual void getValueFromRegisters(uint16_t *registers, int addressOffset); // }; // class SunspecParameterFloat32 : public SunspecParameter { @@ -109,7 +109,7 @@ class SunspecParameterString32 : public SunspecParameter { // public: // SunspecParameterFloat32(std::string name, int registerAddressOffset, int registerSize); -// virtual void setValueFromRegisters(uint16_t *registers, int addressOffset); +// virtual void getValueFromRegisters(uint16_t *registers, int addressOffset); // }; // class SunspecParameterEnum16 : public SunspecParameter { @@ -118,7 +118,7 @@ class SunspecParameterString32 : public SunspecParameter { // public: // SunspecParameterEnum16(std::string name, int registerAddressOffset, int registerSize); -// virtual void setValueFromRegisters(uint16_t *registers, int addressOffset); +// virtual void getValueFromRegisters(uint16_t *registers, int addressOffset); // }; #endif \ No newline at end of file diff --git a/src/hoymiles/dtu.cpp b/src/hoymiles/dtu.cpp index 96cdd5c..85859fa 100644 --- a/src/hoymiles/dtu.cpp +++ b/src/hoymiles/dtu.cpp @@ -90,6 +90,7 @@ void Dtu::updateMicroinverters(std::vector ¶metersToGet, bool a std::pair microinverterPair = this->getMicroinverterBySerialNumber(*microinvertersToGetIterator); if (microinverterPair.second) { microinverterPair.first->updateParameters(parametersToGet, allParameters); + microinverterPair.first->updateStatusParameters(); } microinvertersToGetIterator++; } @@ -111,14 +112,37 @@ void Dtu::printMicroinverters(std::vector ¶metersToGet, bool al std::cout << " " << "Microinverter: " << microinverterPair.first->serialNumber << std::endl; std::cout << " " << "Microinverter Data Age: " << microinverterPair.first->age << std::endl; if (printTodayProduction) { - std::cout << " " << "TodayProduction: " << microinverterPair.first->getTodayProduction() << std::endl; + std::cout << " " << "TodayProduction: " << microinverterPair.first->getTodayProduction() << "Wh" << std::endl; } if (printTotalProduction) { - std::cout << " " << "TotalProduction: " << microinverterPair.first->getTotalProduction() << std::endl; + std::cout << " " << "TotalProduction: " << microinverterPair.first->getTotalProduction() << "Wh" << std::endl; } microinverterPair.first->printPorts(parametersToGet, allParameters, shortNames); std::cout << std::endl; } microinvertersToGetIterator++; } +} + +void Dtu::setStatusMicroinverters(uint16_t value, std::string statusName, std::vector& microinvertersToSet) { + if (microinvertersToSet.empty()) { + std::vector::iterator microinvertersIterator = this->microinverters.begin(); + while (microinvertersIterator != this->microinverters.end()) { + microinvertersToSet.push_back(microinvertersIterator->serialNumber); + microinvertersIterator++; + } + } + + std::vector::iterator microinvertersToSetIterator = microinvertersToSet.begin(); + while(microinvertersToSetIterator != microinvertersToSet.end()) { + std::pair microinverterPair = this->getMicroinverterBySerialNumber(*microinvertersToSetIterator); + if(microinverterPair.second) { + microinverterPair.first->setStatusWholeMicroinverter(value, statusName); + } + microinvertersToSetIterator++; + } +} + +bool Dtu::empty() { + return this->microinverters.empty(); } \ No newline at end of file diff --git a/src/hoymiles/microinverter.cpp b/src/hoymiles/microinverter.cpp index 993599e..31e2044 100644 --- a/src/hoymiles/microinverter.cpp +++ b/src/hoymiles/microinverter.cpp @@ -13,6 +13,8 @@ Microinverter::Microinverter(std::shared_ptr modbus, int startAddr this->startAddress = startAddress; this->serialNumber = serialNumber; + this->statusStartAddress = (((this->startAddress - 0x4000) / 0x0019) * 6) + 0xd006; + this->age = 0; } @@ -43,7 +45,37 @@ void Microinverter::updateParameters(std::vector ¶metersToGet, } for (int i{0}; i < portsToRead; i++) { - this->ports.at(i).setParametersFromMicroinverterArray(registers, i * 0x0019); + this->ports.at(i + portsRead).setParametersFromMicroinverterArray(registers, i * 0x0019); + } + + portsRead += portsToRead; + } +} + +void Microinverter::updateStatusParameters() { + int portsRead = 0; + while (portsRead < this->ports.size()) { + int portsToRead = 0; + while (portsToRead * 6 < (128 - 6) && (portsToRead + portsRead) < this->ports.size()) { + portsToRead++; + } + + int registersToRead = (portsToRead * 6); + uint16_t registers[registersToRead]; + + int registerCount; + registerCount = this->modbus.get()->modbus_read_holding_registers(this->statusStartAddress + (portsRead * 6), registersToRead, registers); + + if (registerCount != 0) { + this->age++; + return; + } + else { + this->age = 0; + } + + for (int i{0}; i < portsToRead; i++) { + this->ports.at(i + portsRead).setStatusesFromMicroinverterArray(registers, i * 6); } portsRead += portsToRead; @@ -81,4 +113,27 @@ long long Microinverter::getTotalProduction() { } return result; +} + +void Microinverter::setStatus(std::vector> portsToSet, std::string statusName) { + std::vector>::iterator portsToSetIterator = portsToSet.begin(); + while(portsToSetIterator != portsToSet.end()) { + try { + if(this->ports.at(portsToSetIterator->first).getStatusByName(statusName).second) { + this->ports.at(portsToSetIterator->first).getStatusByName(statusName).first->writeValue(portsToSetIterator->second, *this->modbus, this->statusStartAddress); + } + } + catch(const std::out_of_range& outOfRange) { + std::cerr << outOfRange.what() << std::endl; + } + portsToSetIterator++; + } +} + +void Microinverter::setStatusWholeMicroinverter(uint16_t value, std::string statusName) { + if(this->ports.begin() != this->ports.end()) { + if(this->ports.begin()->getStatusByName(statusName).second) { + this->ports.begin()->getStatusByName(statusName).first.get()->writeValue(value, *this->modbus, this->ports.begin()->statusPortStartAddress); + } + } } \ No newline at end of file diff --git a/src/hoymiles/port.cpp b/src/hoymiles/port.cpp index 7b1a518..72f839c 100644 --- a/src/hoymiles/port.cpp +++ b/src/hoymiles/port.cpp @@ -12,6 +12,8 @@ Port::Port(int portStartAddress) { this->portStartAddress = portStartAddress; + this->statusPortStartAddress = (((this->portStartAddress - 0x4000) / 0x0019) * 6) + 0xd006; + this->currentFixed = false; this->populateParameters(); @@ -47,6 +49,10 @@ void Port::populateParameters() { this->parameters.push_back(std::make_shared()); this->parameters.push_back(std::make_shared()); + + this->statusParameters.push_back(std::make_shared()); + + this->statusParameters.push_back(std::make_shared()); } std::pair, bool> Port::getParameterByName(std::string name) { @@ -65,6 +71,22 @@ std::pair, bool> Port::getParameterByName(std::st return result; } +std::pair, bool> Port::getStatusByName(std::string name) { + std::pair, bool> result; + result.second = false; + + std::vector>::iterator parametersIterator = this->statusParameters.begin(); + while (parametersIterator != this->statusParameters.end() && !result.second) { + if (parametersIterator->get()->name == name) { + result.first = *parametersIterator; + result.second = true; + } + parametersIterator++; + } + + return result; +} + void Port::fixCurrent() { if (this->currentFixed) { return; @@ -80,7 +102,7 @@ void Port::fixCurrent() { if (this->getParameterByName("pvPower").first->getValue().first.f > this->getParameterByName("pvVoltage").first->getValue().first.f * this->getParameterByName("pvCurrentMI").first->getValue().first.f) { this->parameters.erase(std::find(this->parameters.begin(), this->parameters.end(), this->getParameterByName("pvCurrentHM").first)); } else { - this->parameters.erase(std::find(this->parameters.begin(), this->parameters.end(), this->getParameterByName("pvCurrentM").first)); + this->parameters.erase(std::find(this->parameters.begin(), this->parameters.end(), this->getParameterByName("pvCurrentMI").first)); } this->currentFixed = true; } @@ -125,8 +147,17 @@ void Port::fixCurrent() { void Port::setParametersFromMicroinverterArray(uint16_t *registers, int addressOffset) { std::vector>::iterator parametersIterator = this->parameters.begin(); - while(parametersIterator != this->parameters.end()) { - parametersIterator->get()->setValueFromRegisters(registers, addressOffset); + while (parametersIterator != this->parameters.end()) { + parametersIterator->get()->getValueFromRegisters(registers, addressOffset); + parametersIterator++; + } + this->fixCurrent(); +} + +void Port::setStatusesFromMicroinverterArray(uint16_t *registers, int addressOffset) { + std::vector>::iterator parametersIterator = this->statusParameters.begin(); + while (parametersIterator != this->statusParameters.end()) { + parametersIterator->get()->getValueFromRegisters(registers, addressOffset); parametersIterator++; } } @@ -149,7 +180,7 @@ void Port::printParameters(std::vector ¶metersToGet, bool allPa } while (parametersToGetIterator != parametersToGet.end()) { - if(*parametersToGetIterator == "microinverterSerialNumber") { + if (*parametersToGetIterator == "microinverterSerialNumber") { parametersToGetIterator++; continue; } @@ -158,14 +189,35 @@ void Port::printParameters(std::vector ¶metersToGet, bool allPa parameterPair = this->getParameterByName(*parametersToGetIterator); if (parameterPair.second) { std::cout << " "; - if(shortNames) { + if (shortNames) { std::cout << parameterPair.first->shortName; - } - else { + } else { std::cout << parameterPair.first->name; } std::cout << ": " << parameterPair.first->getOutputValue() << " |"; } parametersToGetIterator++; } + + std::vector>::iterator statusesToGetIterator = this->statusParameters.begin(); + while (statusesToGetIterator != this->statusParameters.end()) { + std::cout << " "; + if (shortNames) { + std::cout << statusesToGetIterator->get()->shortName; + } else { + std::cout << statusesToGetIterator->get()->name; + } + std::cout << ": " << statusesToGetIterator->get()->getOutputValue() << " |"; + statusesToGetIterator++; + } +} + +void Port::turnOff(class modbus &modbus) { this->getStatusByName("onOff").first.get()->writeValue(0, modbus, this->statusPortStartAddress); } + +bool Port::isOff(class modbus &modbus) { + if (this->getStatusByName("onOff").first.get()->getValue().first.i == 1) { + return true; + } else { + return false; + } } \ No newline at end of file diff --git a/src/hoymiles/portParameters/portParameters.cpp b/src/hoymiles/portParameters/portParameters.cpp index 39237cb..d7bbb43 100644 --- a/src/hoymiles/portParameters/portParameters.cpp +++ b/src/hoymiles/portParameters/portParameters.cpp @@ -5,43 +5,47 @@ #include "portParameters.h" -PortParameterMicroinverterSerialNumber::PortParameterMicroinverterSerialNumber() : PortParameterInt("microinverterSerialNumber", "mSN", "", 0x0001, 3) {} +PortParameterMicroinverterSerialNumber::PortParameterMicroinverterSerialNumber() : PortParameterInt("microinverterSerialNumber", "mSN", "", true, false, 0x0001, 3) {} -void PortParameterMicroinverterSerialNumber::setValueFromRegisters(uint16_t *registers, int addressOffset) { +void PortParameterMicroinverterSerialNumber::getValueFromRegisters(uint16_t *registers, int addressOffset) { std::string readValueString = ""; for (int i{0}; i < this->registerSize; i++) { std::stringstream readValueStringStream; - readValueStringStream << std::hex << (int) ((registers[addressOffset + this->parameterAddressOffset + i] & 0xff00) > 8); + readValueStringStream << std::hex << (int) ((registers[addressOffset + this->parameterAddressOffset + i] & 0xff00) >> 8); readValueStringStream << std::hex << (int) (registers[addressOffset + this->parameterAddressOffset + i] & 0x00ff); readValueString.append(readValueStringStream.str()); } this->value.i = std::stoll(readValueString); } -PortParameterPortNumber::PortParameterPortNumber() : PortParameterInt("portNumber", "pN", "", 0x0004, 1) {} +PortParameterPortNumber::PortParameterPortNumber() : PortParameterInt("portNumber", "pN", "", true, false, 0x0004, 1) {} -PortParameterPvVoltage::PortParameterPvVoltage() : PortParameterFloat("pvVoltage", "pvU", "V", 1, 0x0005, 1) {} +PortParameterPvVoltage::PortParameterPvVoltage() : PortParameterFloat("pvVoltage", "pvU", "V", true, false, 1, 0x0005, 1) {} -PortParameterPvCurrentMi::PortParameterPvCurrentMi() : PortParameterFloat("pvCurrentMI", "pvIMI", "A", 1, 0x0006, 1) {} +PortParameterPvCurrentMi::PortParameterPvCurrentMi() : PortParameterFloat("pvCurrentMI", "pvIMI", "A", true, false, 1, 0x0006, 1) {} -PortParameterPvCurrentHm::PortParameterPvCurrentHm() : PortParameterFloat("pvCurrentHM", "pvIHM", "A", 2, 0x0006, 1) {} +PortParameterPvCurrentHm::PortParameterPvCurrentHm() : PortParameterFloat("pvCurrentHM", "pvIHM", "A", true, false, 2, 0x0006, 1) {} -PortParameterGridVoltage::PortParameterGridVoltage() : PortParameterFloat("gridVoltage", "gU", "V", 1, 0x0007, 1) {} +PortParameterGridVoltage::PortParameterGridVoltage() : PortParameterFloat("gridVoltage", "gU", "V", true, false, 1, 0x0007, 1) {} -PortParameterGridFrequency::PortParameterGridFrequency() : PortParameterFloat("gridFrequency", "gF", "Hz", 2, 0x0008, 1) {} +PortParameterGridFrequency::PortParameterGridFrequency() : PortParameterFloat("gridFrequency", "gF", "Hz", true, false, 2, 0x0008, 1) {} -PortParameterPvPower::PortParameterPvPower() : PortParameterFloat("pvPower", "pvP", "W", 1, 0x0009, 1) {} +PortParameterPvPower::PortParameterPvPower() : PortParameterFloat("pvPower", "pvP", "W", true, false, 1, 0x0009, 1) {} -PortParameterTodayProduction::PortParameterTodayProduction() : PortParameterInt("todayProduction", "tdP", "Wh", 0x000A, 1) {} +PortParameterTodayProduction::PortParameterTodayProduction() : PortParameterInt("todayProduction", "tdP", "Wh", true, false, 0x000A, 1) {} -PortParameterTotalProduction::PortParameterTotalProduction() : PortParameterInt("totalProduction", "ttP", "Wh", 0x000B, 2) {} +PortParameterTotalProduction::PortParameterTotalProduction() : PortParameterInt("totalProduction", "ttP", "Wh", true, false, 0x000B, 2) {} -PortParameterTemperature::PortParameterTemperature() : PortParameterFloat("temperature", "t", "C", 1, 0x000D, 1) {} +PortParameterTemperature::PortParameterTemperature() : PortParameterFloat("temperature", "t", "C", true, false, 1, 0x000D, 1) {} -PortParameterOperatingStatus::PortParameterOperatingStatus() : PortParameterInt("operatingStatus", "oS", "", 0x000e, 1) {} +PortParameterOperatingStatus::PortParameterOperatingStatus() : PortParameterInt("operatingStatus", "oS", "", true, false, 0x000e, 1) {} -PortParameterAlarmCode::PortParameterAlarmCode() : PortParameterInt("alarmCode", "aC", "", 0x000f, 1) {} +PortParameterAlarmCode::PortParameterAlarmCode() : PortParameterInt("alarmCode", "aC", "", true, false, 0x000f, 1) {} -PortParameterAlarmCount::PortParameterAlarmCount() : PortParameterInt("alarmCount", "aCnt", "", 0x0010, 1) {} +PortParameterAlarmCount::PortParameterAlarmCount() : PortParameterInt("alarmCount", "aCnt", "", true, false, 0x0010, 1) {} -PortParameterLinkStatus::PortParameterLinkStatus() : PortParameterInt("linkStatus", "lS", "", 0x011, 1) {} \ No newline at end of file +PortParameterLinkStatus::PortParameterLinkStatus() : PortParameterInt("linkStatus", "lS", "", true, false, 0x011, 1) {} + +PortParameterOnOff::PortParameterOnOff() : PortParameterInt("onOff", "of", "", true, true, 0x0000, 1) {} + +PortParameterLimitActivePower::PortParameterLimitActivePower() : PortParameterInt("limitActivePower", "lAP", "%", true, true, 0x0001, 1) {} \ No newline at end of file diff --git a/src/hoymiles/portParameters/portParametersGeneric.cpp b/src/hoymiles/portParameters/portParametersGeneric.cpp index bdea96f..eb34b9d 100644 --- a/src/hoymiles/portParameters/portParametersGeneric.cpp +++ b/src/hoymiles/portParameters/portParametersGeneric.cpp @@ -8,46 +8,37 @@ #include "portParametersGeneric.h" -PortParameter::PortParameter(std::string name, std::string shortName, std::string unit, uint16_t parameterAddressOffset, int registerSize) { +PortParameter::PortParameter(std::string name, std::string shortName, std::string unit, bool r, bool w, uint16_t parameterAddressOffset, int registerSize) { this->name = name; this->shortName = shortName; this->unit = unit; + this->r = r; + this->w = w; + this->parameterAddressOffset = parameterAddressOffset; this->registerSize = registerSize; - - // this->age = 0; } PortParameter::~PortParameter() {} -void PortParameter::setValueFromRegisters(uint16_t *readArray, int portOffset) {} +void PortParameter::getValueFromRegisters(uint16_t *readArray, int portOffset) {} std::pair PortParameter::getValue() { return std::pair(this->value, this->valueType); } +PortParameter& PortParameter::writeValue(uint16_t value, class modbus& modbus, int portStartAddress) { + int writeCount; + writeCount = modbus.modbus_write_register(this->parameterAddressOffset + portStartAddress, value); + return *this; +} + std::string PortParameter::getOutputValue() { return "yeet"; } -// void PortParameter::updateValue(std::shared_ptr modbus, uint16_t portStartAddress) { -// uint16_t readArray[this->registerSize]; -// int registerCount; - -// registerCount = modbus.get()->modbus_read_holding_registers(portStartAddress + this->parameterAddressOffset, this->registerSize, readArray); - -// if(registerCount != 0){ -// this->age++; -// } -// else{ -// registerCount = this->registerSize; -// this->setValueFromRegisters(readArray, registerCount); -// this->age = 0; -// } -// } - -PortParameterFloat::PortParameterFloat(std::string name, std::string shortName, std::string unit, int decimalPlaces, uint16_t parameterAddressOffset, int registerSize) : PortParameter(name, shortName, unit, parameterAddressOffset, registerSize) { +PortParameterFloat::PortParameterFloat(std::string name, std::string shortName, std::string unit, bool r, bool w, int decimalPlaces, uint16_t parameterAddressOffset, int registerSize) : PortParameter(name, shortName, unit, r, w, parameterAddressOffset, registerSize) { this->decimalPlaces = decimalPlaces; this->valueType = Float; @@ -55,7 +46,7 @@ PortParameterFloat::PortParameterFloat(std::string name, std::string shortName, this->value.f = 0; } -void PortParameterFloat::setValueFromRegisters(uint16_t *registers, int addressOffset) { +void PortParameterFloat::getValueFromRegisters(uint16_t *registers, int addressOffset) { std::string readValueString{""}; for(int i{0}; iregisterSize; i++) { std::stringstream readValueStringStream; @@ -71,13 +62,13 @@ std::string PortParameterFloat::getOutputValue() { return valueStringStream.str().append(this->unit.c_str()); } -PortParameterInt::PortParameterInt(std::string name, std::string shortName, std::string unit, uint16_t parameterAddressOffset, int registerSize) : PortParameter(name, shortName, unit, parameterAddressOffset, registerSize) { +PortParameterInt::PortParameterInt(std::string name, std::string shortName, std::string unit, bool r, bool w, uint16_t parameterAddressOffset, int registerSize) : PortParameter(name, shortName, unit, r, w, parameterAddressOffset, registerSize) { this->valueType = Int; this->value.i = 0; } -void PortParameterInt::setValueFromRegisters(uint16_t *registers, int addressOffset) { +void PortParameterInt::getValueFromRegisters(uint16_t *registers, int addressOffset) { std::string readValueString{""}; for (int i{0}; i < this->registerSize; i++) { std::stringstream readValueStringStream; diff --git a/src/hoymiles/sunspec.cpp b/src/hoymiles/sunspec.cpp index d50cd50..3a94b0c 100644 --- a/src/hoymiles/sunspec.cpp +++ b/src/hoymiles/sunspec.cpp @@ -23,7 +23,7 @@ void Sunspec::setValues() { std::vector>::iterator parametersIterator = this->parameters.begin(); while(parametersIterator != this->parameters.end()) { - parametersIterator->get()->setValueFromRegisters(registers, 0); + parametersIterator->get()->getValueFromRegisters(registers, 0); parametersIterator++; } } diff --git a/src/hoymiles/sunspecParameters/sunspecParameters.cpp b/src/hoymiles/sunspecParameters/sunspecParameters.cpp index 1312b08..1b68bdd 100644 --- a/src/hoymiles/sunspecParameters/sunspecParameters.cpp +++ b/src/hoymiles/sunspecParameters/sunspecParameters.cpp @@ -8,7 +8,7 @@ SunspecParameterManufacturer::SunspecParameterManufacturer() : SunspecParameterS this->valueType = string32; } -void SunspecParameterManufacturer::setValueFromRegisters(uint16_t *registers, int addressOffset) { +void SunspecParameterManufacturer::getValueFromRegisters(uint16_t *registers, int addressOffset) { std::string readValue; for(int i{0}; iregisterSize; i++) { diff --git a/src/hoymiles/sunspecParameters/sunspecParametersGeneric.cpp b/src/hoymiles/sunspecParameters/sunspecParametersGeneric.cpp index c825428..93186e5 100644 --- a/src/hoymiles/sunspecParameters/sunspecParametersGeneric.cpp +++ b/src/hoymiles/sunspecParameters/sunspecParametersGeneric.cpp @@ -8,10 +8,10 @@ SunspecParameter::SunspecParameter(std::string name, int registerAddressOffset, this->registerSize = registerSize; } -void SunspecParameter::setValueFromRegisters(uint16_t *registers, int addressOffset) {} +void SunspecParameter::getValueFromRegisters(uint16_t *registers, int addressOffset) {} std::pair SunspecParameter::getValue() {} SunspecParameterString32::SunspecParameterString32(std::string name, int registerAddressOffset, int registerSize) : SunspecParameter(name, registerAddressOffset, registerSize) {} -void SunspecParameterString32::setValueFromRegisters(uint16_t *registers, int addressOffset) {} \ No newline at end of file +void SunspecParameterString32::getValueFromRegisters(uint16_t *registers, int addressOffset) {} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 0b22ab6..3c461e3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,11 @@ #include #include +#include +#include +#include #include #include #include -#include -#include -#include #include "CLI11.hpp" #include "modbus.h" @@ -19,11 +19,13 @@ int main(int argc, char **argv) { signal(SIGTERM, sigHandler); signal(SIGABRT, sigHandler); - std::string version{"v2.1"}; + std::string version{"v2.2w"}; std::cout << version << std::endl; CLI::App hoymilesClient{"Client for DTU-Pro/DTU-ProS"}; + hoymilesClient.set_version_flag("-v,--version", version); + std::string ipAddress{"127.0.0.1"}; std::string ipAddressHelp{"ipv4 address of DTU {default: " + ipAddress + "}"}; hoymilesClient.add_option("-i,--ip_address", ipAddress, ipAddressHelp)->required()->group("Networking"); @@ -33,7 +35,8 @@ int main(int argc, char **argv) { hoymilesClient.add_option("-p,--port", port, portHelp)->group("Networking"); std::vector parametersToGet{}; - std::string parametersToGetHelp{"List of parameters to fetch, delimited by ','; possible parameters:\n - pvVoltage [pvU]\n - pvCurrentMI [pvIMI]\n - pvCurrentHM [pvIHM]\n - gridVoltage [gU]\n - gridFrequency [gF]\n - pvPower [gP]\n - todayProduction [tdP]\n - totalProduction [ttP]\n - temperature [t]\n - operatingStatus [oS]\n - alarmCode [aC]\n - alarmCount [aCnt]\n - linkStatus [lS]"}; + std::string parametersToGetHelp{"List of parameters to fetch, delimited by ','; possible parameters:\n - pvVoltage [pvU]\n - pvCurrentMI [pvIMI]\n - pvCurrentHM [pvIHM]\n - gridVoltage [gU]\n - gridFrequency [gF]\n - pvPower [gP]\n - " + "todayProduction [tdP]\n - totalProduction [ttP]\n - temperature [t]\n - operatingStatus [oS]\n - alarmCode [aC]\n - alarmCount [aCnt]\n - linkStatus [lS]"}; hoymilesClient.add_option>("-P,--parameters", parametersToGet, parametersToGetHelp)->delimiter(',')->group("Parameters"); bool allParameters = false; @@ -44,9 +47,9 @@ int main(int argc, char **argv) { std::string shortNamesHelp{"Print short parameter names"}; hoymilesClient.add_flag("-s,--short", shortNames, shortNamesHelp)->group("Parameters"); - std::vector microinvertersToGet{}; - std::string microinvertersToGetHelp{"List of microinverters to fetch, delimited by ','; if omitted, all are fetched"}; - hoymilesClient.add_option>("-m,--microinverters", microinvertersToGet, microinvertersToGetHelp)->delimiter(',')->group("Microinverters"); + std::vector microinvertersToChoose{}; + std::string microinvertersToChooseHelp{"List of microinverters to work on, delimited by ','; if omitted, all are selected"}; + hoymilesClient.add_option>("-m,--microinverters", microinvertersToChoose, microinvertersToChooseHelp)->delimiter(',')->group("Microinverters"); bool microinvertersGetTodayProduction{false}; std::string microinvertersGetTodayProductionHelp{"Show today production for microinverters"}; @@ -60,6 +63,17 @@ int main(int argc, char **argv) { std::string ignoreNotConnectedHelp{"Ignore conn_error"}; hoymilesClient.add_flag("-I,--ignore_conn_error", ignoreNotConnected, ignoreNotConnectedHelp)->group("Debug"); + bool writeMode = false; + std::string writeModeHelp{"Write instead of read"}; + hoymilesClient.add_flag("-w,--write", writeMode, writeModeHelp)->group("Write"); + + uint16_t writeValue; + std::string writeValueHelp{"Value to write"}; + hoymilesClient.add_option("-V,--value", writeValue, writeModeHelp)->group("Write")->needs(hoymilesClient.get_option("-w")); + + std::string writeStatusName{}; + std::string writeStatusNameHelp{"Status to write"}; + hoymilesClient.add_option("-S,--status", writeStatusName, writeStatusName)->group("Write")->needs(hoymilesClient.get_option("-w")); try { hoymilesClient.parse(argc, argv); @@ -72,20 +86,35 @@ int main(int argc, char **argv) { Dtu dtu{ipAddress.c_str(), port}; auto endTime = std::chrono::high_resolution_clock::now(); std::cout << "DTU construction time: " << std::chrono::duration_cast(endTime - startTime).count() << "ms" << std::endl; + std::cout << std::endl << std::endl; + + while (!writeMode && (!dtu.empty() && ((dtu.isConnected() || ignoreNotConnected) && (!parametersToGet.empty() || allParameters)))) { + time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); - while ((dtu.isConnected() || ignoreNotConnected) && (!parametersToGet.empty() || allParameters)) { startTime = std::chrono::high_resolution_clock::now(); - dtu.updateMicroinverters(parametersToGet, allParameters, microinvertersToGet); + dtu.updateMicroinverters(parametersToGet, allParameters, microinvertersToChoose); endTime = std::chrono::high_resolution_clock::now(); + + std::cout << "Pass time: " << std::put_time(localtime(&now), "%F %T") << std::endl; std::cout << "DTU update time: " << std::chrono::duration_cast(endTime - startTime).count() << "ms" << std::endl; - dtu.printMicroinverters(parametersToGet, allParameters, microinvertersToGet, shortNames, microinvertersGetTodayProduction, microinvertersGetTotalProduction); + dtu.printMicroinverters(parametersToGet, allParameters, microinvertersToChoose, shortNames, microinvertersGetTodayProduction, microinvertersGetTotalProduction); std::cout << std::endl; } // if(dtu.modbusError()) { // std::cerr << dtu.modbusErrorMessage() << std::endl; // } + if(writeMode) { + std::cout << "Starting DTU write" << std::endl; + + startTime = std::chrono::high_resolution_clock::now(); + dtu.setStatusMicroinverters(writeValue, writeStatusName, microinvertersToChoose); + endTime = std::chrono::high_resolution_clock::now(); + + std::cout << "DTU write time: " << std::chrono::duration_cast(endTime - startTime).count() << "ms" << std::endl; + } + return 0; }