Skip to content

Commit 31896df

Browse files
committed
Show topic info in BLE tool
1 parent b262db7 commit 31896df

1 file changed

Lines changed: 117 additions & 3 deletions

File tree

docs/b2500.html

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,17 @@
6161

6262
.info-container {
6363
display: grid;
64-
grid-template-columns: 100px 1fr;
64+
grid-template-columns: 190px 1fr;
6565
row-gap: 10px;
6666
margin-top: 20px;
6767
}
6868

69+
.topic-mono {
70+
font-family: monospace;
71+
font-size: 13px;
72+
word-break: break-all;
73+
}
74+
6975
label {
7076
font-weight: bold;
7177
}
@@ -181,6 +187,7 @@ <h2>Debug Logs</h2>
181187
<div id="logs" class="logs"></div>
182188
</div>
183189

190+
<script src="https://cdn.jsdelivr.net/npm/aes-js@3.1.2/index.min.js"></script>
184191
<script>
185192
// BLE Service and Characteristic UUIDs
186193
const SERVICE_UUID = '0000ff00-0000-1000-8000-00805f9b34fb';
@@ -612,6 +619,23 @@ <h2>Debug Logs</h2>
612619
deviceType.textContent = parsedInfo.type || 'Unknown';
613620
deviceId.textContent = parsedInfo.id || 'Unknown';
614621
deviceMac.textContent = parsedInfo.mac || 'Unknown';
622+
// Always show both topics, and set correct threshold in label
623+
let mac = parsedInfo.mac || '';
624+
let type = parsedInfo.type || '';
625+
let macNoColons = mac.replace(/:/g, '').toLowerCase();
626+
let encryptedMac = calculateNewVersionTopicId(macNoColons);
627+
let oldTopic = `hame_energy/${type}/device/${macNoColons}/ctrl`;
628+
let newTopic = `marstek_energy/${type}/device/${encryptedMac}/ctrl`;
629+
let oldAppTopic = `hame_energy/${type}/App/${macNoColons}/ctrl`;
630+
let newAppTopic = `marstek_energy/${type}/App/${encryptedMac}/ctrl`;
631+
// Determine threshold
632+
let threshold = /^HMJ-\d+$/i.test(type) ? 108 : 226;
633+
document.getElementById('device-topic-ge-label').textContent = `Topic for firmware >=${threshold}:`;
634+
document.getElementById('device-topic-ge').textContent = newTopic;
635+
document.getElementById('device-topic-ge-app').textContent = newAppTopic;
636+
document.getElementById('device-topic-lt-label').textContent = `Topic for firmware <${threshold}:`;
637+
document.getElementById('device-topic-lt').textContent = oldTopic;
638+
document.getElementById('device-topic-lt-app').textContent = oldAppTopic;
615639
deviceInfo.classList.remove('hidden');
616640

617641
// Update status
@@ -745,8 +769,58 @@ <h2>Debug Logs</h2>
745769
}
746770
}
747771

748-
// Function to analyze a connected device and provide filtering options
749-
// This function was used for debugging but is now removed since we're using a hardcoded filter
772+
// --- Topic Calculation Helpers ---
773+
// AES key and IV for new topic
774+
const NEW_TOPIC_KEY = [33,64,35,36,37,94,38,42,40,41,95,43,123,125,91,93];
775+
const NEW_TOPIC_IV = new Array(16).fill(0);
776+
777+
// Pad to 16 bytes (PKCS7)
778+
function pkcs7Pad(bytes) {
779+
const padLen = 16 - (bytes.length % 16);
780+
const padded = new Uint8Array(bytes.length + padLen);
781+
padded.set(bytes);
782+
padded.fill(padLen, bytes.length);
783+
return padded;
784+
}
785+
786+
// Calculate new version topic encrypted MAC (browser version)
787+
function calculateNewVersionTopicId(mac) {
788+
const aesCbc = new aesjs.ModeOfOperation.cbc(NEW_TOPIC_KEY, NEW_TOPIC_IV);
789+
// MAC is a string, encode as UTF-8 bytes
790+
const macBytes = aesjs.utils.utf8.toBytes(mac);
791+
const padded = pkcs7Pad(macBytes);
792+
const encryptedBytes = aesCbc.encrypt(padded);
793+
return aesjs.utils.hex.fromBytes(encryptedBytes);
794+
}
795+
796+
// --- Topic Calculation Logic ---
797+
function getDeviceTopic(type, version, mac) {
798+
// type: string, version: string or number, mac: string
799+
// If device type is HMJ-X (X is an arbitrary number) and version >=108,
800+
// or if device type is not HMJ-X and version >=226, use new topic
801+
// else use old topic
802+
let topic = '';
803+
let encryptedMac = '';
804+
let macNoColons = (mac || '').replace(/:/g, '').toLowerCase();
805+
let typeUpper = (type || '').toUpperCase();
806+
let versionNum = parseInt(version, 10);
807+
if (/^HMJ-\d+$/i.test(typeUpper)) {
808+
if (versionNum >= 108) {
809+
encryptedMac = calculateNewVersionTopicId(macNoColons);
810+
topic = `marstek_energy/${type}/device/${encryptedMac}/ctrl`;
811+
} else {
812+
topic = `hame_energy/${type}/device/${macNoColons}/ctrl`;
813+
}
814+
} else {
815+
if (versionNum >= 226) {
816+
encryptedMac = calculateNewVersionTopicId(macNoColons);
817+
topic = `marstek_energy/${type}/device/${encryptedMac}/ctrl`;
818+
} else {
819+
topic = `hame_energy/${type}/device/${macNoColons}/ctrl`;
820+
}
821+
}
822+
return topic;
823+
}
750824

751825
// Event listeners
752826
connectButton.addEventListener('click', connectToDevice);
@@ -772,6 +846,46 @@ <h2>Debug Logs</h2>
772846
// Display browser information
773847
log(`Browser: ${navigator.userAgent}`);
774848
}
849+
850+
// --- Add topic display to device info UI ---
851+
// Add rows for both topics and an info note, but use generic placeholders for now
852+
(function addTopicRows() {
853+
const infoContainer = document.querySelector('.info-container');
854+
// For >= threshold
855+
const topicGELabel = document.createElement('div');
856+
topicGELabel.id = 'device-topic-ge-label';
857+
topicGELabel.textContent = 'Topic for firmware >=XXX:';
858+
const topicGEValue = document.createElement('div');
859+
topicGEValue.id = 'device-topic-ge';
860+
topicGEValue.className = 'topic-mono';
861+
infoContainer.appendChild(topicGELabel);
862+
infoContainer.appendChild(topicGEValue);
863+
// App topic for >= threshold
864+
const topicGEAppLabel = document.createElement('div');
865+
topicGEAppLabel.id = 'device-topic-ge-app-label';
866+
const topicGEAppValue = document.createElement('div');
867+
topicGEAppValue.id = 'device-topic-ge-app';
868+
topicGEAppValue.className = 'topic-mono';
869+
infoContainer.appendChild(topicGEAppLabel);
870+
infoContainer.appendChild(topicGEAppValue);
871+
// For < threshold
872+
const topicLTLabel = document.createElement('div');
873+
topicLTLabel.id = 'device-topic-lt-label';
874+
topicLTLabel.textContent = 'Topic for firmware <XXX:';
875+
const topicLTValue = document.createElement('div');
876+
topicLTValue.id = 'device-topic-lt';
877+
topicLTValue.className = 'topic-mono';
878+
infoContainer.appendChild(topicLTLabel);
879+
infoContainer.appendChild(topicLTValue);
880+
// App topic for < threshold
881+
const topicLTAppLabel = document.createElement('div');
882+
topicLTAppLabel.id = 'device-topic-lt-app-label';
883+
const topicLTAppValue = document.createElement('div');
884+
topicLTAppValue.id = 'device-topic-lt-app';
885+
topicLTAppValue.className = 'topic-mono';
886+
infoContainer.appendChild(topicLTAppLabel);
887+
infoContainer.appendChild(topicLTAppValue);
888+
})();
775889
</script>
776890
</body>
777891
</html>

0 commit comments

Comments
 (0)