Skip to content

Commit

Permalink
feat(mitm): transfer errors in mitm mode
Browse files Browse the repository at this point in the history
  • Loading branch information
tspopp committed May 28, 2024
1 parent 5866580 commit 988653b
Show file tree
Hide file tree
Showing 11 changed files with 321 additions and 121 deletions.
11 changes: 10 additions & 1 deletion AquaMQTT/include/config/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,20 @@ constexpr bool OVERRIDE_TIME_AND_DATE_IN_MITM = true;
*/
constexpr bool DEBUG_RAW_SERIAL_MESSAGES = false;

/**
* Change the time interval where all known attributes are published to the MQTT broker.
*/
constexpr uint32_t MQTT_FULL_UPDATE_MS = 1000*60*30;

/**
* Change the fixed time interval where the attributes published to the stats topic are updated.
*/
constexpr uint16_t MQTT_STATS_UPDATE_MS = 5000;

/**
* Self explanatory internal settings: most probably you don't want to change them.
*/
constexpr uint8_t WATCHDOG_TIMEOUT_S = 60;
constexpr uint16_t MQTT_STATS_UPDATE_MS = 5000;
constexpr uint8_t MQTT_MAX_TOPIC_SIZE = 80;
constexpr uint8_t MQTT_MAX_PAYLOAD_SIZE = 255;

Expand Down
6 changes: 0 additions & 6 deletions AquaMQTT/include/message/MainStatusMessage.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,6 @@ class MainStatusMessage

bool errorCodeChanged() const;

void changeUnknownStateA(bool b);

void changeUnknownStateB(bool b);

void hackError();

private:
uint8_t* mData;
bool mHotWaterTempChanged;
Expand Down
2 changes: 2 additions & 0 deletions AquaMQTT/include/message/MessageConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ namespace message
{
constexpr uint8_t HEATPUMP_MAX_FRAME_LENGTH = 40;

constexpr uint8_t MESSAGE_PERIOD_MS = 100;

constexpr uint8_t HMI_MESSAGE_IDENTIFIER = 194;
constexpr uint8_t HMI_MESSAGE_LENGTH = 35;
constexpr uint8_t MAIN_MESSAGE_IDENTIFIER = 193;
Expand Down
25 changes: 18 additions & 7 deletions AquaMQTT/include/task/ControllerTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@
namespace aquamqtt
{

enum class ControllerTaskState
{
AWAITING_67,
AWAITING_193,
CHECK_FOR_HMI_TRIGGER,
AWAITING_74,
};

class ControllerTask
{
public:
Expand All @@ -23,14 +31,17 @@ class ControllerTask

void loop();

void sendMessage194();

static void flushReadBuffer();

private:
bool mFlagSeen67;
bool mFlagSeen193;
FrameBuffer mBuffer;
unsigned long mLastStatisticsUpdate;
uint8_t mTransferBuffer[message::HEATPUMP_MAX_FRAME_LENGTH];
FastCRC16 mCRC;
uint64_t mMessagesSent;
FrameBuffer mBuffer;
unsigned long mLastStatisticsUpdate;
uint8_t mTransferBuffer[message::HEATPUMP_MAX_FRAME_LENGTH];
FastCRC16 mCRC;
uint64_t mMessagesSent;
ControllerTaskState mState;
};
} // namespace aquamqtt

Expand Down
21 changes: 21 additions & 0 deletions AquaMQTT/include/task/HMITask.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@
namespace aquamqtt
{

enum class HMITaskState
{
REQUESTING_194,
SLEEP_194,
SENDING_67,
SLEEP_67,
SENDING_193,
SLEEP_193,
SENDING_74,
SLEEP_74,
};

class HMITask
{
public:
Expand All @@ -23,12 +35,21 @@ class HMITask

void loop();

static void flushReadBuffer();

void sendMessage67();
void sendMessage193();
void sendMessage74();

private:
FrameBuffer mBuffer;
unsigned long mLastStatisticsUpdate;
unsigned long mLastMessageSent;
uint8_t mLastEmittedRequestId;
uint8_t mTransferBuffer[message::HEATPUMP_MAX_FRAME_LENGTH];
FastCRC16 mCRC;
uint64_t mMessagesSent;
HMITaskState mState;
};
} // namespace aquamqtt

Expand Down
14 changes: 10 additions & 4 deletions AquaMQTT/include/task/MQTTTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,17 @@ class MQTTTask

static void messageReceived(String& topic, String& payload);

void updateMainStatus();
void updateHMIStatus();
void updateEnergyStats();
void updateMainStatus(bool triggerFullUpdate);
void updateHMIStatus(bool triggerFullUpdate);
void updateEnergyStats(bool triggerFullUpdate);
void updateErrorStatus();
void updateStats();

private:
uint8_t mTransferBuffer[message::HEATPUMP_MAX_FRAME_LENGTH];
uint8_t mTopicBuffer[config::MQTT_MAX_TOPIC_SIZE];
uint8_t mPayloadBuffer[config::MQTT_MAX_PAYLOAD_SIZE];
unsigned long mLastStatsUpdate;
unsigned long mLastFullUpdate;
WiFiClient mWiFiClient;
MQTTClient mMQTTClient;
Expand All @@ -56,7 +57,12 @@ class MQTTTask
void publishString(const char* subtopic, const char* topic, const char* value, bool retained = false);
void publishi(const char* subtopic, const char* topic, int value, bool retained = false);
void publishul(const char* subtopic, const char* topic, unsigned long value, bool retained = false);
void publishul(const char* subtopic_1, const char* subtopic_2, const char* topic, unsigned long value, bool retained = false);
void publishul(
const char* subtopic_1,
const char* subtopic_2,
const char* topic,
unsigned long value,
bool retained = false);
};
} // namespace aquamqtt

Expand Down
6 changes: 3 additions & 3 deletions AquaMQTT/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,17 @@ void setup()
// if listener mode is set in configuration, just read the DHW traffic from a single One-Wire USART instance
if (OPERATION_MODE == LISTENER)
{
// reads 194, 193 and 67 message and notifies the mqtt task
// reads 194, 193, 67 and 74 message and notifies the mqtt task
listenerTask.spawn();
}
// if man-in-the-middle mode is set in configuration, there are two physical One-Wire USART instances
// and AquaMQTT forwards (modified) messages from one to another
else
{
// reads 194 message from the hmi controller, writes 193 and 67 to the hmi controller
// reads 194 message from the hmi controller, writes 193, 67 and 74 to the hmi controller
hmiTask.spawn();

// reads 193 and 67 from the main controller, writes 194 to the main controller
// reads 193, 67 and 74 from the main controller, writes 194 to the main controller
controllerTask.spawn();
}

Expand Down
3 changes: 2 additions & 1 deletion AquaMQTT/src/message/ErrorMessage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ ErrorMessage::ErrorMessage(uint8_t* data) : mData(data)

bool ErrorMessage::isEmpty()
{
for (int i = 0; i < ERROR_MESSAGE_LENGTH; ++i)
// i == 1, since we skip the first byte which is length field and always != 0
for (int i = 1; i < ERROR_MESSAGE_LENGTH; ++i)
{
if (mData[i] != 0)
return false;
Expand Down
104 changes: 67 additions & 37 deletions AquaMQTT/src/task/ControllerTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ namespace aquamqtt

ControllerTask::ControllerTask()
: mBuffer(false, true, true, true, "controller")
, mFlagSeen193(false)
, mFlagSeen67(false)
, mLastStatisticsUpdate(0)
, mTransferBuffer{ 0 }
, mCRC()
, mMessagesSent(0){}
, mMessagesSent(0)
, mState(ControllerTaskState::AWAITING_67)
{
}

void ControllerTask::spawn()
{
Expand All @@ -40,7 +41,7 @@ void ControllerTask::spawn()
}
}

void ControllerTask::setup() // NOLINT(*-convert-member-functions-to-static)
void ControllerTask::setup() // NOLINT(*-convert-member-functions-to-static)
{
Serial2.begin(9550, SERIAL_8N2, aquamqtt::config::GPIO_MAIN_RX, aquamqtt::config::GPIO_MAIN_TX);
}
Expand All @@ -54,51 +55,57 @@ void ControllerTask::loop()
{
int valRead = Serial2.read();

if (mFlagSeen67 && mFlagSeen193)
switch (mState)
{
if (valRead == aquamqtt::message::HMI_MESSAGE_IDENTIFIER)
case ControllerTaskState::AWAITING_67:
if (mBuffer.pushByte(valRead) == aquamqtt::message::ENERGY_MESSAGE_IDENTIFIER)
{
mState = ControllerTaskState::AWAITING_193;
}
break;
case ControllerTaskState::AWAITING_193:
{
mFlagSeen67 = false;
mFlagSeen193 = false;

if (HMIStateProxy::getInstance().copyFrame(aquamqtt::message::HMI_MESSAGE_IDENTIFIER, mTransferBuffer))
int processedMessageId = mBuffer.pushByte(valRead);
if (processedMessageId == aquamqtt::message::MAIN_MESSAGE_IDENTIFIER)
{
mState = ControllerTaskState::CHECK_FOR_HMI_TRIGGER;
}
else if (processedMessageId != 0)
{
uint16_t crc = mCRC.ccitt(mTransferBuffer, aquamqtt::message::HMI_MESSAGE_LENGTH);
Serial2.write(mTransferBuffer, aquamqtt::message::HMI_MESSAGE_LENGTH);
Serial2.write((uint8_t) (crc >> 8));
Serial2.write((uint8_t) (crc & 0xFF));
Serial2.flush();
mMessagesSent++;
mState = ControllerTaskState::AWAITING_67;
}
else
break;
}
case ControllerTaskState::CHECK_FOR_HMI_TRIGGER:
if (valRead == aquamqtt::message::ERROR_MESSAGE_IDENTIFIER)
{
Serial.println("[main] no hmi message yet, cannot forward");
mBuffer.pushByte(valRead);
mState = ControllerTaskState::AWAITING_74;
continue;
}

// flush read buffer
while (Serial2.available())
if (valRead == aquamqtt::message::HMI_MESSAGE_IDENTIFIER)
{
Serial2.read();
sendMessage194();
flushReadBuffer();
}
continue;
}
else

mState = ControllerTaskState::AWAITING_67;
break;
case ControllerTaskState::AWAITING_74:
{
mFlagSeen67 = false;
mFlagSeen193 = false;
int processedMessageId = mBuffer.pushByte(valRead);
if (processedMessageId == aquamqtt::message::ERROR_MESSAGE_IDENTIFIER)
{
mState = ControllerTaskState::CHECK_FOR_HMI_TRIGGER;
}
else if (processedMessageId != 0)
{
mState = ControllerTaskState::AWAITING_67;
}
break;
}
}

int message = mBuffer.pushByte(valRead);
if (message == aquamqtt::message::ENERGY_MESSAGE_IDENTIFIER)
{
mFlagSeen67 = true;
mFlagSeen193 = false;
}
else if (message == aquamqtt::message::MAIN_MESSAGE_IDENTIFIER)
{
mFlagSeen193 = true;
}
}

DHWState::getInstance().updateFrameBufferStatistics(
Expand Down Expand Up @@ -128,5 +135,28 @@ void ControllerTask::loop()
mLastStatisticsUpdate = millis();
}
}
void ControllerTask::flushReadBuffer()
{
while (Serial2.available())
{
Serial2.read();
}
}
void ControllerTask::sendMessage194()
{
if (HMIStateProxy::getInstance().copyFrame(message::HMI_MESSAGE_IDENTIFIER, mTransferBuffer))
{
uint16_t crc = mCRC.ccitt(mTransferBuffer, message::HMI_MESSAGE_LENGTH);
Serial2.write(mTransferBuffer, message::HMI_MESSAGE_LENGTH);
Serial2.write((uint8_t) (crc >> 8));
Serial2.write((uint8_t) (crc & 0xFF));
Serial2.flush();
mMessagesSent++;
}
else
{
Serial.println("[main] no hmi message yet, cannot forward");
}
}

} // namespace aquamqtt
Loading

0 comments on commit 988653b

Please sign in to comment.