aboutsummaryrefslogtreecommitdiff
path: root/src/protocol_18/client.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/protocol_18/client.cc')
-rw-r--r--src/protocol_18/client.cc216
1 files changed, 216 insertions, 0 deletions
diff --git a/src/protocol_18/client.cc b/src/protocol_18/client.cc
new file mode 100644
index 0000000..d42c24a
--- /dev/null
+++ b/src/protocol_18/client.cc
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include <memory>
+#include <utility>
+#include <sstream>
+#include <iomanip>
+#include <cmath>
+#include <stdexcept>
+
+#include "client.h"
+#include "types.h"
+#include "defines.h"
+#include "../protocol/exceptions.h"
+#include "response.h"
+#include "../voltronic/crc.h"
+
+#define MKRESPONSE(type) std::shared_ptr<response_type::BaseResponse>(new response_type::type(raw, rawSize))
+
+#define RESPONSE_CASE(type) \
+ case CommandType::Get ## type: \
+ response = MKRESPONSE(type); \
+ break; \
+
+
+namespace p18 {
+
+std::shared_ptr<response_type::BaseResponse> Client::execute(int commandType, std::vector<std::string>& arguments) {
+ auto type = static_cast<CommandType>(commandType);
+
+ std::ostringstream buf;
+ buf << std::setfill('0');
+
+ bool isSetCommand = commandType >= 100;
+
+ auto pos = raw_commands.find(type);
+ if (pos == raw_commands.end())
+ throw std::runtime_error("packedCommand " + std::to_string(commandType) + " not found");
+
+ std::string packedCommand = pos->second;
+ std::string packedArguments = packArguments(type, arguments);
+
+ size_t len = sizeof(voltronic::CRC) + 1 + packedCommand.size() + packedArguments.size();
+
+ buf << "^";
+ buf << (isSetCommand ? "S" : "P");
+ buf << std::setw(3) << len;
+ buf << packedCommand;
+ buf << packedArguments;
+
+ std::string packed = buf.str();
+
+ auto result = runOnDevice(packed);
+ std::shared_ptr<response_type::BaseResponse> response;
+
+ const auto raw = result.first;
+ const auto rawSize = result.second;
+
+ switch (type) {
+ RESPONSE_CASE(ProtocolID)
+ RESPONSE_CASE(CurrentTime)
+ RESPONSE_CASE(TotalGenerated)
+ RESPONSE_CASE(YearGenerated)
+ RESPONSE_CASE(MonthGenerated)
+ RESPONSE_CASE(DayGenerated)
+ RESPONSE_CASE(SeriesNumber)
+ RESPONSE_CASE(CPUVersion)
+ RESPONSE_CASE(RatedInformation)
+ RESPONSE_CASE(GeneralStatus)
+ RESPONSE_CASE(WorkingMode)
+ RESPONSE_CASE(FaultsAndWarnings)
+ RESPONSE_CASE(FlagsAndStatuses)
+ RESPONSE_CASE(Defaults)
+ RESPONSE_CASE(AllowedChargingCurrents)
+ RESPONSE_CASE(AllowedACChargingCurrents)
+ RESPONSE_CASE(ParallelRatedInformation)
+ RESPONSE_CASE(ParallelGeneralStatus)
+ RESPONSE_CASE(ACChargingTimeBucket)
+ RESPONSE_CASE(ACLoadsSupplyTimeBucket)
+
+ case CommandType::SetLoads:
+ case CommandType::SetFlag:
+ case CommandType::SetDefaults:
+ case CommandType::SetBatteryMaxChargingCurrent:
+ case CommandType::SetBatteryMaxACChargingCurrent:
+ case CommandType::SetACOutputFreq:
+ case CommandType::SetBatteryMaxChargingVoltage:
+ case CommandType::SetACOutputRatedVoltage:
+ case CommandType::SetOutputSourcePriority:
+ case CommandType::SetBatteryChargingThresholds:
+ case CommandType::SetChargingSourcePriority:
+ case CommandType::SetSolarPowerPriority:
+ case CommandType::SetACInputVoltageRange:
+ case CommandType::SetBatteryType:
+ case CommandType::SetOutputModel:
+ case CommandType::SetBatteryCutOffVoltage:
+ case CommandType::SetSolarConfig:
+ case CommandType::ClearGenerated:
+ case CommandType::SetDateTime:
+ case CommandType::SetACChargingTimeBucket:
+ case CommandType::SetACLoadsSupplyTimeBucket:
+ response = MKRESPONSE(SetResponse);
+ break;
+ }
+
+ if (!response->validate())
+ throw protocol::InvalidResponseError("validate() failed");
+
+ response->unpack();
+ return std::move(response);
+}
+
+std::string Client::packArguments(p18::CommandType commandType, std::vector<std::string>& arguments) {
+ std::ostringstream buf;
+ buf << std::setfill('0');
+
+ switch (commandType) {
+ case CommandType::GetYearGenerated:
+ case CommandType::SetOutputSourcePriority:
+ case CommandType::SetSolarPowerPriority:
+ case CommandType::SetACInputVoltageRange:
+ case CommandType::SetBatteryType:
+ case CommandType::SetLoads:
+ buf << arguments[0];
+ break;
+
+ case CommandType::GetMonthGenerated:
+ case CommandType::GetDayGenerated:
+ buf << arguments[0];
+ for (int i = 1; i <= (commandType == CommandType::GetMonthGenerated ? 1 : 2); i++)
+ buf << std::setw(2) << std::stoi(arguments[i]);
+ break;
+
+ case CommandType::GetParallelGeneralStatus:
+ case CommandType::GetParallelRatedInformation:
+ buf << std::stoi(arguments[0]);
+ break;
+
+ case CommandType::SetFlag:
+ buf << (arguments[1] == "1" ? "E" : "D");
+ buf << arguments[0];
+ break;
+
+ case CommandType::SetBatteryMaxChargingCurrent:
+ case CommandType::SetBatteryMaxACChargingCurrent:
+ buf << arguments[0] << ",";
+ buf << std::setw(3) << std::stoi(arguments[1]);
+ break;
+
+ case CommandType::SetACOutputFreq:
+ buf << std::setw(2) << std::stoi(arguments[0]);
+ break;
+
+ case CommandType::SetBatteryMaxChargingVoltage:
+ case CommandType::SetBatteryChargingThresholds: {
+ for (int i = 0; i < 2; i++) {
+ double val = std::stod(arguments[i]);
+ buf << std::setw(3) << (int)round(val*10);
+ if (i == 0)
+ buf << ",";
+ }
+ break;
+ }
+
+ case CommandType::SetACOutputRatedVoltage: {
+ buf << std::setw(4) << (std::stoi(arguments[0])*10);
+ break;
+ }
+
+ case CommandType::SetChargingSourcePriority:
+ case CommandType::SetOutputModel:
+ buf << arguments[0] << "," << arguments[1];
+ break;
+
+ case CommandType::SetBatteryCutOffVoltage: {
+ double v = std::stod(arguments[0]);
+ buf << std::setw(3) << ((int)round(v*10));
+ break;
+ }
+
+ case CommandType::SetSolarConfig: {
+ size_t len = arguments[0].size();
+ buf << std::setw(2) << len << arguments[0];
+ if (len < 20) {
+ for (int i = 0; i < 20-len; i++)
+ buf << "0";
+ }
+ break;
+ }
+
+ case CommandType::SetDateTime: {
+ for (int i = 0; i < 6; i++) {
+ int val = std::stoi(arguments[i]);
+ if (i == 0)
+ val -= 2000;
+ buf << std::setw(2) << val;
+ }
+ break;
+ }
+
+ case CommandType::SetACChargingTimeBucket:
+ case CommandType::SetACLoadsSupplyTimeBucket:
+ for (int i = 0; i < 4; i++) {
+ buf << std::setw(2) << std::stoi(arguments[i]);
+ if (i == 1)
+ buf << ",";
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return buf.str();
+}
+
+} \ No newline at end of file