Skip to content

Commit

Permalink
Add initial support for the AnkerMake M5C
Browse files Browse the repository at this point in the history
This change allows to monitor MQTT messages of the AnkerMake M5C on the
command line as well as observe the printer status via the Web GUI.
It is also possible to send print jobs from your slicer to the printer
without using AnkerMake Slicer or Studio (see README.md).
The M5's additional hardware is still expected to exist, therefore the
Web GUI will still pretend to wait for a camera connection, for example.
This will have to be fixed in the future.
  • Loading branch information
treitmayr committed Jan 21, 2024
1 parent bcf6855 commit 0d0c88b
Showing 1 changed file with 30 additions and 11 deletions.
41 changes: 30 additions & 11 deletions libflagship/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,19 @@ def parse(cls, p):
m7, p = u8.parse(p)
packet_type, p = MqttPktType.parse(p)
packet_num, p = u16le.parse(p)
time, p = u32le.parse(p)
device_guid, p = String.parse(p, 37)
padding, p = Bytes.parse(p, 11)
if m5 == 2:
# AnkerMake M5
time, p = u32le.parse(p)
device_guid, p = String.parse(p, 37)
padding, p = Bytes.parse(p, 11)
elif m5 == 1:
# AnkerMake M5C
time = 0 # does not seem to be sent for M5C
device_guid = "none" # still present for M5C???
padding, p = Bytes.parse(p, 12) # first 6 bytes seem to change with each packet, rest is all zeros
else:
raise ValueError(f"Unsupported mqtt message format (expected 1 or 2, but found {m5})")

data, p = Tail.parse(p)
return cls(signature=signature, size=size, m3=m3, m4=m4, m5=m5, m6=m6, m7=m7, packet_type=packet_type, packet_num=packet_num, time=time, device_guid=device_guid, padding=padding, data=data), p

Expand All @@ -119,9 +129,12 @@ def pack(self):
p += u8.pack(self.m7)
p += MqttPktType.pack(self.packet_type)
p += u16le.pack(self.packet_num)
p += u32le.pack(self.time)
p += String.pack(self.device_guid, 37)
p += Bytes.pack(self.padding, 11)
if self.m5 == 2:
p += u32le.pack(self.time)
p += String.pack(self.device_guid, 37)
p += Bytes.pack(self.padding, 11)
elif self.m5 == 1:
p += Bytes.pack(self.padding, 12)
p += Tail.pack(self.data)
return p

Expand All @@ -131,17 +144,23 @@ class MqttMsg(_MqttMsg):
@classmethod
def parse(cls, p, key):
p = mqtt_checksum_remove(p)
if p[6] != 2:
raise ValueError(f"Unsupported mqtt message format (expected 2, but found {p[6]})")
body, data = p[:64], mqtt_aes_decrypt(p[64:], key)
try:
body_len = {1:24, 2:64}[p[6]]
except KeyError:
raise ValueError(f"Unsupported mqtt message format (expected 1 or 2, but found {p[6]})")
body, data = p[:body_len], mqtt_aes_decrypt(p[body_len:], key)
res = super().parse(body + data)
assert res[0].size == (len(p) + 1)
return res

def pack(self, key):
data = mqtt_aes_encrypt(self.data, key)
self.size = 64 + len(data) + 1
body = super().pack()[:64]
try:
body_len = {1:24, 2:64}[self.m5]
except KeyError:
raise ValueError(f"Unsupported mqtt message format (expected 1 or 2, but found {self.m5})")
self.size = body_len + len(data) + 1
body = super().pack()[:body_len]
final = mqtt_checksum_add(body + data)
return final

Expand Down

0 comments on commit 0d0c88b

Please sign in to comment.