I came across tekelectron’s project, where he successfully managed to read data from the USB port of his SmartView2 in home display. I have the same IHD myself, so I thought I would give this a go. This project is the result of what I found.
The USB port on the rear of the SmartView2 in home display is just a standard USB micro connector. This port is used for charging the device, as it has an internal battery, though mine is left plugged in all the time. Connecting the device to a PC produces the “USB Device Not Recognized” error, so it is obviously not intended to work as a USB device.
According to tekelectron, the USB port produces serial data, and a bit of probing with my oscilloscope proved this to be true. I couldn’t decipher much from this, so I went ahead and used my Arduino Mega to read the data, and simply send this to my PC to display it in the serial console of the IDE. This is the program I used.
const int BUFFER_SIZE = 385;
byte buf[BUFFER_SIZE];
int i;
void setup() {
Serial.begin(115200);
Serial1.begin(115200);
}
void loop() {
// wait for incoming data
while (Serial1.available() == 0) {
// do nothing
}
// read the incoming bytes:
int rlen = Serial1.readBytes(buf, BUFFER_SIZE);
// prints the received data
for(i = 0; i < rlen; i++){
Serial.print(buf[i], HEX);
Serial.print(",");
}
Serial.print("\n");
}
The baud rate was based on tekelectron’s initial finding, and worked perfectly. I have since found that the buffer size is not important.
This is a cleaned up sample of what I captured, as a simple text file.
The Arduino code places the comma between each byte, so it can be read easily as a CSV file. I used Putty to log the data, and then used Excel to add leading zeros to any single digits (0 – F). This makes the data much easier to read.
Next was the more difficult part. Having the data in Excel meant that I could filter it, and look for patterns and repetitions. Some of the data translates into text, as it is simply ASCII values. In the snip above, several of the lines begin with 72, 61. The section up to 0A translates as below.
72 61 6E 20 43 43 35 31 3A 31 3A 37 30 32 20 31 32 0A = ran CC51:1:702 12
This really doesn’t mean anything to me at all.
Using asciitable.com, it became clearer which sections were text, and which sections might contain data. What I found is that the data sections begin with F1, and end with F2. I decided to ignore the ASCII sections, and focus on the data between the F1 start points, and the F2 end points. I wrote a bit of script to filter this out for me, and then did several hours of recording over a couple of days.
Using the filter function of Excel, I was able to fish out each of the distinct packets of data from the log. With only one packet at a time showing, it was easy to see which bytes changed, and which stayed the same. The bytes that changed could possibly relate to some piece of information that my meters had read. Noting that tekelectron had read the bytes as little endian, I followed the same, and converted the most common packet’s changing bytes to decimal. Sure enough, this matched the current electricity wattage!
Below is a complete list of the packets I picked out, and what I have discovered about them (underlined bytes). It is a little bit pieced together sorry, as my findings didn’t come all at once, and I took data from several days. The packets are in the order they are transmitted. They are repeated in order, with the current electricity wattage being transmitted the most frequently. I have removed the F1 and F2 markers.
Transmitted approximately once every 8 seconds
04 01 02 07 07 02 00 30 00 00 04 00 2A DB 00 00
Current electricity wattage (W) (may be 3 bytes)
00 05 B7 24 ← This packet is transmitted after every packet, and has 2 bytes that change.
Transmitted once after 5 repeats of above
04 00 02 07 00 00 00 25 74 7D 1B 00 00 00 01 0C 00 22 E6 46 00 14 00 00 30 02 00 02 00 18 02
Gas meter reading (m³) Daily gas used
00 05 B2 17
04 00 05 07 1C 05 00 25 86 79 02 00 00 00 00 00 00 19 94 0C
Gas cost today (£)
00 05 B3 1A
04 01 05 07 1C 05 00 25 82 49 02 00 00 00 00 00 00 19 94 0C
Electricity cost today (£)
00 05 B4 1C
04 01 02 07 00 00 00 25 03 BD 68 00 00 00 01 04 00 22 C3 0D 00 14 00 00 30 02 00 02 00 18 00
Electricity meter reading (kWh) Daily electricity used
00 05 B3 1A
05 00 02 07 08 8B
00 05 B4 1C
04 01 02 07 07 02 00 30 00 00 04 00 2A DB 00 00
Current electricity wattage (W)
00 05 B4 1C
01 01 50 89 62 2D 0B 00 00 00
03 01 02 07 07 00 00 50 89 62 2D 00 08 07 01 00 0B 00 00
00 05 B3 1A ← I removed this packet from the section below.
Transmitted once every 29 repeats of all above
04 00 02 07 04 0A 00 18 50 00 0A 00 23 AC 9C 36 00
04 00 02 07 03 0C 00 22 DF 46 00 32 0C 00 22 CF 4E 02 42 0C 00 23 36 28 0E 00
Gas used yesterday (kWh)
04 00 05 07 30 05 00 25 71 2B 02 00 00 00 40 05 00 25 EF 83 3D 00 00 00
04 01 08 07 01 01 00 41 0E 4F 63 74 6F 70 75 73 20 45 6E 65 72 67 79 02 01 00 41 0D 30 38 30 38 20 31 36 34 20 31 30 38 38
String “Octopus Energy” “0808 164 1088”
04 01 05 07 30 05 00 25 6A 50 02 00 00 00 40 05 00 25 E3 45 33 00 00 00
04 01 02 07 04 0A 00 18 50 00 0A 00 23 CB C1 2E 00
04 01 02 07 03 04 00 22 80 16 00 32 04 00 22 0F 81 00 42 04 00 23 EF 1D 02 00
Electricity used yesterday (kWh)
04 00 02 07 30 0C 00 22 66 3C 00 40 0C 00 23 81 37 07 00 11 03 00 41 04 30 30 30 30
04 00 05 07 1E 05 00 25 24 79 02 00 00 00 32 05 00 25 6B 0D 14 00 00 00 42 05 00 25 A4 CE 75 00 00 00
04 01 08 07 00 04 00 23 88 13 00 00 01 04 00 23 20 4E 00 00
04 01 05 07 1E 05 00 25 24 42 03 00 00 00 32 05 00 25 13 A6 13 00 00 00 42 05 00 25 C6 A7 53 00 00 00
04 01 02 07 30 04 00 22 01 0E 00 40 04 00 23 C5 4B 01 00 11 03 00 41 40 30 30 30 30
I have highlighted the parts that change, and what they match up to on the SmartView2 IHD. What I have discovered is that the second byte of the packet starts with 01 for an electricity reading, and 00 for a gas reading. Each packet with an electricity reading has a matching packet for the same reading of the gas (I think). There isn’t a packet for the current wattage of the gas though, and on the IHD, this only updates every half hour or so. In some of the packets, only two bytes ever change, and not three. If these packets have a matching packet from the other energy source reading, and three bytes change in this, then I have highlighted the same three bytes in these packets. This is probably because more energy was drawn from one energy source, compared to the other. There is something not right with the gas and electricity used yesterday. I thought I had this sussed at one time. The gas matches up, but the electricity doesn’t. I have taken the reading out of my project for now.
How does this relate to Home Assistant? Below is the code that I have written (taking snips from tekelectron and others), which reads the data packets, and sends the readings to a webpage using AJAX. I have switched over to using an ESP8266 for this, on an ESP-01 module. Only the current electricity wattage is sent to Home Assistant at the moment, using MQTT. The code does work well, but I have discovered that there are errors sent in the packets (the occasional extra value sent). Either that, or I drew 30,000 watts of electricity at one point during the day! I don’t have a secret time travelling DeLorean stashed away.
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <PubSubClient.h> //MQTT messaging
#include "Webpage.h" //Wepage containing readings
const char* ssid = "Your SSID Here";
const char* password = "Your SSID Password Here";
const char* mqtt_server = "MQTT Broker IP";
const char* mqtt_user = "MQTT User";
const char* mqtt_password = "MQTT Password";
char msg1[10];
ESP8266WebServer server(80);
WiFiClient espClient;
PubSubClient client(espClient);
String XMLData;
byte pktStart[1], pktEnd[1], packet[42];
long int eMeterRead1, eMeterRead2, eMeterRead3, eMeterRead4, gMeterRead1, gMeterRead2, gMeterRead3;
String seMeterRead1 = "0", seMeterRead2 = "0", seMeterRead3 = "0", seMeterRead4 = "0", sgMeterRead1 = "0", sgMeterRead2 = "0", sgMeterRead3 = "0";
String sPacket;
int header;
int i, j, bufLen;
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("MQTT connecting...");
// Create a client ID
String clientId = "ESP8266-Client-";
clientId += String(WiFi.macAddress());
// Attempt to connect
if (client.connect(clientId.c_str(), mqtt_user, mqtt_password)) {
Serial.print("Connected.");
Serial.println();
// Once connected, publish an announcement...
client.publish("energy/meterread", "Meter Readings.");
} else {
Serial.print("Failed. Retrying in 5 seconds...");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
// Configure serial ports
Serial.begin(115200);
Serial.setTimeout(4000);
delay(10);
// Connect to WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
// Print the IP address
Serial.print("Use this URL to connect: ");
Serial.print("http://");
Serial.print(WiFi.localIP());
Serial.println("/");
server.on("/", SendWebsite);
server.on("/emeter", SendXML);
// Start the server
server.begin();
Serial.println("Server started");
Serial.println("Connecting to MQTT server");
client.setServer(mqtt_server, 1883);
}
void loop() {
// Reconnect to MQTT if not connected
if (!client.connected()){
reconnect();
}
client.loop();
// Wait for something in the serial buffer
while(Serial.available() > 0){
i = 0;
// Look for F1 start indicator
Serial.readBytes(pktStart, 1);
if(pktStart[0] == 0xF1){
// Read the next byte of the packet until F2 is received
Serial.readBytes(pktEnd, 1);
while(pktEnd[0] != 0xF2){
packet[i] = pktEnd[0];
i++;
Serial.readBytes(pktEnd, 1);
}
}
// Search packet if it was greater than two bytes
if(i > 2){
sPacket = "";
for(i = 0; i < sizeof(packet); i++) {
sPacket = sPacket + String(packet[i], HEX) + ",";
}
header = packet[0] + packet[1] + packet[2] + packet[3] + packet[4];
switch(header){
case 0x0D:
Serial.print("G Meter Reading: ");
gMeterRead1 = (packet[10] * pow(16, 4)) + (packet[9] * pow(16,2)) + packet[8];
sgMeterRead1 = gMeterRead1;
Serial.print(sgMeterRead1);
Serial.print(" m³");
Serial.print(" " + sPacket + "\n");
break;
case 0x2C:
Serial.print("G Cost Today: ");
gMeterRead2 = (packet[10] * pow(16, 4)) + (packet[9] * pow(16,2)) + packet[8];
sgMeterRead2 = gMeterRead2;
Serial.print(sgMeterRead2);
Serial.print(" " + sPacket + "\n");
break;
case 0x10:
Serial.print("Gas Used Yesterday: ");
gMeterRead3 = (packet[10] * pow(16, 4)) + (packet[9] * pow(16,2)) + packet[8];
sgMeterRead3 = gMeterRead3;
Serial.print(sgMeterRead3);
Serial.print(" kWh");
Serial.print(" " + sPacket + "\n");
break;
case 0x15:
Serial.print("Current Wattage: ");
eMeterRead1 = (packet[14] << 8) + packet[13];
seMeterRead1 = eMeterRead1;
sprintf(msg1, "%u", eMeterRead1);
client.publish("energy/meterread", msg1);
Serial.print(seMeterRead1);
Serial.print(" Watts");
Serial.print(" " + sPacket + "\n");
break;
case 0x0E:
Serial.print("E Meter Reading: ");
eMeterRead4 = (packet[10] * pow(16, 4)) + (packet[9] * pow(16,2)) + packet[8];
seMeterRead4 = eMeterRead4;
Serial.print(seMeterRead4);
Serial.print(" kWh");
Serial.print(" " + sPacket + "\n");
break;
case 0x2D:
Serial.print("E Cost Today: ");
eMeterRead2 = (packet[10] * pow(16, 4)) + (packet[9] * pow(16,2)) + packet[8];
seMeterRead2 = eMeterRead2;
Serial.print(seMeterRead2);
Serial.print(" " + sPacket + "\n");
break;
//case 0x11:
// Serial.print("Electric Used Yesterday: ");
// eMeterRead3 = (packet[10] * pow(16, 4)) + (packet[9] * pow(16,2)) + packet[8];
// seMeterRead3 = eMeterRead3;
// Serial.print(seMeterRead3);
// Serial.print(" kWh");
// Serial.print(" " + sPacket + "\n");
// break;
default:
break;
}
}
}
server.handleClient();
}
void SendWebsite() {
server.send(200, "text/html", PAGE_MAIN);
}
void SendXML() {
XMLData = "<?xml version=\'1.0\'?>";
XMLData += "<readings>";
XMLData += "<emeter>" + seMeterRead4 + "</emeter>";
XMLData += "<ewattage>" + seMeterRead1 + "</ewattage>";
XMLData += "<edcost>" + seMeterRead2 + "</edcost>";
XMLData += "<eyesterday>" + seMeterRead3 + "</eyesterday>";
XMLData += "<gmeter>" + sgMeterRead1 + "</gmeter>";
//XMLData += "<gwattage>1234</gwattage>";
XMLData += "<gdcost>" + sgMeterRead2 + "</gdcost>";
XMLData += "<gyesterday>" + sgMeterRead3 + "</gyesterday>";
XMLData += "</readings>";
server.send(200, "text/xml", XMLData);
}
The code for webpage.h is below
const char PAGE_MAIN[] PROGMEM = R"=====(
<!DOCTYPE HTML>
<html lang="en" class="js-focus-visible">
<title>SmartView2 Readings</title>
<body onload="loadDoc()">
<script type = "text/javascript">
function loadDoc() {
const xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
updateReadings(this);
}
}
xhttp.open("GET", "/emeter");
xhttp.send();
setTimeout(loadDoc, 200);
}
function updateReadings(xml) {
var xmlDoc = xml.responseXML;
var x = xmlDoc.getElementsByTagName("readings");
document.getElementById("emeter").innerHTML = x[0].getElementsByTagName("emeter")[0].childNodes[0].nodeValue;
document.getElementById("ewattage").innerHTML = x[0].getElementsByTagName("ewattage")[0].childNodes[0].nodeValue;
document.getElementById("edcost").innerHTML = x[0].getElementsByTagName("edcost")[0].childNodes[0].nodeValue;
document.getElementById("eyesterday").innerHTML = x[0].getElementsByTagName("eyesterday")[0].childNodes[0].nodeValue;
document.getElementById("gmeter").innerHTML = x[0].getElementsByTagName("gmeter")[0].childNodes[0].nodeValue;
document.getElementById("gdcost").innerHTML = x[0].getElementsByTagName("gdcost")[0].childNodes[0].nodeValue;
document.getElementById("gyesterday").innerHTML = x[0].getElementsByTagName("gyesterday")[0].childNodes[0].nodeValue;
}
</script>
<div>
<h2>Electricity</h2>
<p></p>
<p>Current Meter Reading (kWh):<div id="emeter">0</div></p>
<p>Current Wattage (W):<div id="ewattage">0</div></p>
<p>Current Cost Today (£):<div id="edcost">0</div></p>
<p>Use Yesterday (kWh):<div id="eyesterday">0</div></p>
</div>
<div>
<h2>Gas</h2>
<p></p>
<p>Current Meter Reading (m³):<div id="gmeter">0</div></p>
<!--<p>Current Wattage (W):<div id="gwattage">0</div></p>-->
<p>Current Cost Today (£):<div id="gdcost">0</div></p>
<p>Use Yesterday (kWh):<div id="gyesterday">0</div></p>
</div>
</body>
</html>
)=====";
This is a work in process, and needs some error checking adding. Maybe you will be able to add your insight into the project, and better decode the packets. Maybe they already have some kind of parity check in them, which just needs to be decoded. If you have a SmartView2, and would like to give this a go, then let me know how this turns out, and the results you get. Other IHDs may give out similar data too. Apart from tekelectron’s post, I can’t find any other write up of anybody trying this with their IHD. It goes without saying that all of the above has been done using my knowledge of electronics and coding. Please don’t hold me responsible if it doesn’t work out the same for you in your trials, or anything stops working.
Thanks for reading.