--- /dev/null
+#!/usr/bin/python
+# Copyright (c) 2017, Tobias Mueller tm(at)tm3d.de
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the
+# distribution.
+# * All advertising materials mentioning features or use of this
+# software must display the following acknowledgement: This product
+# includes software developed by tm3d.de and its contributors.
+# * Neither the name of tm3d.de nor the names of its contributors may
+# be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+import time
+import subprocess
+import sys
+devInfo= ["","temperature","pressure","illuminance","humidity","constant","voltage","current","VOC","counter","CO2","resistance"]
+devUnit= ["","°C","hPa","lux","%","","V","mA","ppm","","ppm","kOhm"]
+
+devController=["","Old code","Attiny84A","Attiny44","Atmega328"]
+
+devChip=["","DS18B20","DS2438","DS2438","DS2438","DS2450","Thermoelement","SHT21","SHT25","DHT22","HIH9021","HDC1080","HIH4030","HIH5030","BMP280","MAX44009","CDM7160","MAX1164/TGS8100","TGS8100","DS2423"]
+
+
+def calcValue(code,vn,V):
+ if code==0:
+ return V[vn]
+ if code==1:
+ return V[vn] / 16.0;
+ if code==2:
+ return V[vn]/1.6;
+ if code==3:
+ return V[vn]*0.2 + 700;
+ if code==4:
+ return exp(V[vn] / 160.0);
+ if code==5:
+ return V[vn]*62.5 + 55000;
+ if code==6:
+ return V[vn] / 256.0;
+ if code==7:
+ return ((float(V[2]) / float(V[1]) - 0.16) / 0.0062) / (1.0546 - 0.00216*V[0]/256.0);
+ if code==8:
+ return V[vn] / 100.0;
+ if code==9:
+ return V[vn] / 65535.0*5.1;
+ if code==10:
+ return V[vn] / 65535.0*2.55;
+ if code==11:
+ return V[vn] / 65535.0*1.1;
+ if code==12:
+ return V[vn] / 10.0;
+ if code==13:
+ return V[vn];
+ if code==14:
+ return (V[vn] - 32767.0) / 100.0;
+ if code==15:
+ return exp((V[vn]-32767.0)/1000.0);
+ if code==16:
+ return V[vn]/32.0;
+ return 0;
+
+
+
+def owcom(dev,send,rc):
+ res=[]
+ try:
+ f=open("/sys/bus/w1/devices/%s/rw" %(dev),"r+b",0)
+ except IOError:
+ l=subprocess.check_output("rmmod w1_therm",shell=True)
+ f=open("/sys/bus/w1/devices/%s/rw" %(dev),"r+b",0)
+ f.write("".join(map(chr, send)))
+ if (rc!=0):
+ res=map(ord,f.read(rc))
+ f.close()
+ return res
+
+
+def crc8(arr):
+ lscrc=0x0;
+ for v in arr:
+ bit=1;
+ while bit<256:
+ if (v&bit)==bit:
+ lb=1
+ else:
+ lb=0
+ if (lscrc&1)!=lb:
+ lscrc=(lscrc>>1)^0x8c
+ else:
+ lscrc=(lscrc>>1)
+ bit=bit*2
+ return (lscrc==0)
+
+
+oddparity = [ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 ]
+
+
+def crc16(arr):
+ crc16=0
+ for cdata in arr:
+ cdata = (cdata ^ (crc16 & 0xff)) & 0xff;
+ crc16 = crc16>>8;
+ if (oddparity[cdata & 0xf] ^ oddparity[cdata >> 4]):
+ crc16 = crc16 ^ 0xc001;
+ cdata = (cdata << 6)&0xffff;
+ crc16 = crc16 ^ cdata;
+ cdata = (cdata << 1)&0xffff;
+ crc16 = crc16^cdata;
+ #r=crc16==0xB001
+ return (crc16==0xB001)
+
+
+def ow_fconvert(b1, b2):
+ tsht = b1 | (b2 << 8)
+ if (b2 & 0x080):
+ tsht=-(tsht&0x7FFF)
+ return tsht
+
+
+def testnr(s):
+ for c in s.lower()[:]:
+ if not((c) in ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','-']):
+ return False
+ return True
+
+def addid(id,val):
+ for i in range(7):
+ id[i+1]=id[i+1]+val
+ if id[i+1]>254:
+ id[i+1]=id[i+1]-254
+ val=1
+ else:
+ return id
+ return id
+#
+
+def owfind(famcodes):
+ l=subprocess.check_output("ls /sys/bus/w1/devices/", shell=True)
+ dl=[]
+ for g in (l.split("\n")):
+ if len(g)>2:
+ if testnr(g[0:2]):
+ if (g[0:2] in famcodes) or len(famcodes)==0:
+ dl.append(g)
+ print g
+ return dl;
+
+
+class owDevice:
+ raw=[0,0,0,0]
+ values=[0.0,0.0,0.0,0.0]
+ owid=""
+ config=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
+ def __init__(self, owid):
+ self.owid = owid
+
+ def setdefaultConfig(self):
+ raise NotImplementedError()
+
+ def readConfig(self):
+ self.config=owcom(self.owid,[0x85],26)
+ if self.config[0]==0xFF:
+ print("No Deviceconfig. Not a Device form tm3d.de. Set Default");
+ self.setdefaultConfig()
+ else:
+ if self.config[25]==0xFF:
+ if not(crc8(self.config[0:24])):
+ print("CRC Error reading Deviceconfig. Set Default")
+ self.setdefaultConfig()
+ else:
+ if not(crc16([0x85]+self.config)):
+ print("CRC Error reading Deviceconfig. Set Default")
+ self.setdefaultConfig()
+
+ def convertAll(self):
+ raise NotImplementedError()
+
+ def getChips(self):
+ l=[];
+ for i in range(0,4):
+ l.append(devChip[self.config[i+9]])
+ return l
+
+ def getUnits(self):
+ l=[];
+ for i in range(0,4):
+ l.append(devUnit[self.config[i*2]])
+ return l
+
+ def getProperties(self):
+ l=[];
+ for i in range(0,4):
+ l.append(devInfo[self.config[i*2]])
+ return l
+
+
+class owDS2450(owDevice):
+ def setdefaultConfig(self):
+ self.config=[6,9, 6,9, 6,9, 6,9, 0,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0]
+
+ def convertAll(self):
+ ret=owcom(self.owid,[0x3C,0x0F,0x00],2)
+ if not(crc16([0x3C,0x0F,0x00]+ret)):
+ print("CRC ERROR")
+ return
+ time.sleep(1)
+ ret=owcom(self.owid,[0xAA,0x00,0x00],10)
+ if not(crc16([0xAA,0x00,0x00]+ret)):
+ print("CRC ERROR")
+ return
+ for i in range(0,4):
+ self.raw[i]=ret[2*i]|(ret[2*i+1]<<8);
+ for i in range(0,4):
+ self.values[i]=calcValue(self.config[i*2+1],i,self.raw)
+
+
+class owDS18B20(owDevice):
+ def setdefaultConfig(self):
+ self.config=[1,1, 0,0, 0,0, 0,0, 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
+
+ def convertAll(self):
+ owcom(self.owid,[0x44],0)
+ time.sleep(1)
+ ret=owcom(self.owid,[0xBE],9)
+ if not(crc8(ret)):
+ print("CRC ERROR")
+ return
+ self.raw[0]=ow_fconvert(ret[0],ret[1]);
+ self.values[0]=calcValue(self.config[0*2+1],0,self.raw)
+ self.values[1]=0;
+ self.values[2]=0;
+ self.values[3]=0;
+
+class owDS2438(owDevice):
+ def setdefaultConfig(self):
+ self.config=[1,6, 6,8, 4,7, 7,17, 0,2,3,12,4,0,0,0,0,0,0,0,0,0,0,0]
+
+ def readScratchpad(self,page,recall):
+ if (recall):
+ owcom(self.owid,[0xB8,page],0)
+ ret=owcom(self.owid,[0xBE,page],9)
+ if not(crc8(ret)):
+ print("CRC ERROR")
+ return []
+ return ret
+
+ def setConfigByte(self, cb):
+ for i in range(3):
+ owcom(self.owid,[0x4E,0x00,cb],0)
+ sp=self.readScratchpad(0,False)
+ if (sp!=[]):
+ if sp[0]==cb:
+ return True
+ return False
+
+
+
+ def convertAll(self):
+ owcom(self.owid,[0x44],0)
+ time.sleep(0.01)
+ self.setConfigByte(0x08)
+ owcom(self.owid,[0xB4],0)
+ time.sleep(0.01)
+ sp=self.readScratchpad(0,True)
+ temp=ow_fconvert(sp[1],sp[2]);
+ VDD=ow_fconvert(sp[3],sp[4]);
+ self.setConfigByte(0x00)
+ owcom(self.owid,[0xB4],0)
+ time.sleep(0.01)
+ sp=self.readScratchpad(0,True);
+ I=ow_fconvert(sp[5],sp[6]);
+ VAD=ow_fconvert(sp[3],sp[4]);
+ self.raw[0]=temp;
+ self.raw[1]=VDD;
+ self.raw[2]=VAD;
+ self.raw[3]=I;
+ for i in range(0,4):
+ self.values[i]=calcValue(self.config[i*2+1],i,self.raw)
+
+class owDS2423(owDevice):
+ def setdefaultConfig(self):
+ self.config=[9,13, 9,13, 9,13, 9,13, 0,19,19,19,19,0,0,0,0,0,0,0,0,0,0,0]
+
+ def readCounter(self,page):
+ addr=(page<<5)+31
+ ret=owcom(self.owid,[0xA5,addr&0xFF,addr>>8],11)
+ if not(crc16([0xA5,addr&0xFF,addr>>8]+ret)):
+ print("CRC ERROR")
+ return 0
+ c=0
+ for i in range (4):
+ c<<=8;
+ c|=ret[4-i];
+ return c;
+
+
+ def convertAll(self):
+ for i in range(4):
+ self.raw[i]=self.readCounter(i+12);
+ for i in range(0,4):
+ self.values[i]=calcValue(self.config[i*2+1],i,self.raw)
+