Last active
August 17, 2022 17:45
-
-
Save raplin/76da6392f34934738ff865891a7b672f to your computer and use it in GitHub Desktop.
Dependency-free reading of the Hopi HP-9800 power meter (USB version) in python. Windows or Linux etc.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# By Richard Aplin, released into the public domain for any purpose, no warranties implied, 8/17/2022 | |
# | |
# | |
import struct | |
import serial | |
#Super lightweight code to read Hopi HP-9800 power meter | |
class Hopi(object): | |
REGS=[ | |
("Active Power","W"), | |
("RMS Current","A"), | |
("Voltage RMS","V"), | |
("Frequency","Hz"), | |
("Power Factor","pf"), | |
("Annual Power","KWH"), | |
("Active Power","KWH"), | |
("Reactive Power","KWH"), | |
("Load Time","mins"), | |
] | |
def __init__(self,port="COM4"): | |
baud=9600 | |
self.debug=False #True | |
self.ser=serial.Serial(port,baudrate=baud,timeout=1) | |
def crc(self,data): | |
poly=0xa001 | |
crc = 0xFFFF | |
for b in data: | |
cur_byte = 0xFF & ord(b) | |
for _ in range(0, 8): | |
if (crc & 0x0001) ^ (cur_byte & 0x0001): | |
crc = (crc >> 1) ^ poly | |
else: | |
crc >>= 1 | |
cur_byte >>= 1 | |
return struct.pack("<H",crc&0xffff) | |
def read(self): | |
#self.readRegs(4,2) #1,10) | |
self.regs=self.readRegs(0,len(self.REGS)*2) #1,10) | |
def display(self): | |
dmax=99 #can limit how many regs displayed | |
for idx,value in enumerate(self.regs): | |
name,unit=self.REGS[idx] | |
print "%s\t%.3f%s" % (name,value,unit) | |
dmax-=1 | |
if dmax==0: | |
break | |
def phex(self,data): | |
s=" ".join(["%02x" % ord(d) for d in data]) | |
return s | |
def readRegs(self,first,count,addr=1): | |
cmd=0x03 | |
fout=[] | |
m=struct.pack(">BBHH",addr,cmd,first,count) | |
m+=self.crc(m) | |
if self.debug: | |
print "\t>",self.phex(m) | |
self.ser.write(m) | |
replyLen=3+(count*2)+2 | |
r=self.ser.read(replyLen) | |
if self.debug: | |
print "\t<",self.phex(r) | |
if len(r)!=replyLen: | |
print "Bad reply len",len(r) | |
return | |
ccrc=self.crc( r[:-2] ) | |
if ccrc!=r[-2:]: | |
print "bad crc" | |
return | |
addr,f,bcount=struct.unpack(">BBB",r[:3]) | |
if addr==addr and f==cmd: | |
#unpack floats from hopi | |
d=r[3:-2] | |
fpos=0 | |
while fpos<len(d): | |
fpval=d[fpos:fpos+4] | |
v=struct.unpack("<f",fpval)[0] | |
fout.append(v) | |
fpos+=4 | |
#print fpos/2,v | |
return fout | |
else: | |
print "Bad reply" | |
h=Hopi(port="COM4") | |
while True: | |
h.read() | |
h.display() | |
sure thing
Thank you!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi! Could you please consider adding a license? I'm currently porting to python 3 and making some other changes and would like to redistribute them later, but without a license it's "all rights reserved" and I can't legally do so.
Thanks!