2 # Copyright (c) 2017, Tobias Mueller tm(at)tm3d.de
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above copyright
12 # notice, this list of conditions and the following disclaimer in the
13 # documentation and/or other materials provided with the
15 # * All advertising materials mentioning features or use of this
16 # software must display the following acknowledgement: This product
17 # includes software developed by tm3d.de and its contributors.
18 # * Neither the name of tm3d.de nor the names of its contributors may
19 # be used to endorse or promote products derived from this software
20 # without specific prior written permission.
22 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 devInfo= ["","temperature","pressure","illuminance","humidity","constant","voltage","current","VOC","counter","CO2","resistance"]
41 devUnit= ["","°C","hPa","lux","%","","V","mA","ppm","","ppm","kOhm"]
43 devController=["","Old code","Attiny84A","Attiny44","Atmega328"]
45 devChip=["","DS18B20","DS2438","DS2438","DS2438","DS2450","Thermoelement","SHT21","SHT25","DHT22","HIH9021","HDC1080","HIH4030","HIH5030","BMP280","MAX44009","CDM7160","MAX1164/TGS8100","TGS8100","DS2423","SHT35","SHT31"]
48 def calcValue(code,vn,V):
56 return V[vn]*0.2 + 700;
58 return exp(V[vn] / 160.0);
60 return V[vn]*62.5 + 55000;
64 return ((float(V[2]) / float(V[1]) - 0.16) / 0.0062) / (1.0546 - 0.00216*V[0]/256.0);
68 return V[vn] / 65535.0*5.1;
70 return V[vn] / 65535.0*2.55;
72 return V[vn] / 65535.0*1.1;
78 return (V[vn] - 32767.0) / 100.0;
80 return exp((V[vn]-32767.0)/1000.0);
84 return V[vn]*0.2441/1000;
89 def owcom(dev,send,rc):
92 f=open("/sys/bus/w1/devices/%s/rw" %(dev),"r+b",0)
94 l=subprocess.check_output("rmmod w1_therm",shell=True)
95 f=open("/sys/bus/w1/devices/%s/rw" %(dev),"r+b",0)
96 f.write("".join(map(chr, send)))
98 res=map(ord,f.read(rc))
113 lscrc=(lscrc>>1)^0x8c
120 oddparity = [ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 ]
126 cdata = (cdata ^ (crc16 & 0xff)) & 0xff;
128 if (oddparity[cdata & 0xf] ^ oddparity[cdata >> 4]):
129 crc16 = crc16 ^ 0xc001;
130 cdata = (cdata << 6)&0xffff;
131 crc16 = crc16 ^ cdata;
132 cdata = (cdata << 1)&0xffff;
135 return (crc16==0xB001)
138 def ow_fconvert(b1, b2):
139 tsht = b1 | (b2 << 8)
146 for c in s.lower()[:]:
147 if not((c) in ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','-']):
162 def owfind(famcodes):
163 l=subprocess.check_output("ls /sys/bus/w1/devices/", shell=True)
165 for g in (l.split("\n")):
168 if (g[0:2] in famcodes) or len(famcodes)==0:
176 values=[0.0,0.0,0.0,0.0]
178 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]
179 def __init__(self, owid):
182 def setdefaultConfig(self):
183 raise NotImplementedError()
185 def readConfig(self):
186 self.config=owcom(self.owid,[0x85],26)
188 if self.config[0]==0xFF:
189 print("No Deviceconfig. Not a Device form tm3d.de. Set Default");
190 self.setdefaultConfig()
192 if self.config[25]==0xFF:
193 if crc8(self.config[0:24]):
194 print("CRC Error reading Deviceconfig. Set Default")
195 self.setdefaultConfig()
197 if not(crc16([0x85]+self.config)):
198 print("CRC Error reading Deviceconfig. Set Default")
199 self.setdefaultConfig()
201 def convertAll(self):
202 raise NotImplementedError()
207 l.append(devChip[self.config[i+9]])
213 l.append(devUnit[self.config[i*2]])
216 def getProperties(self):
219 l.append(devInfo[self.config[i*2]])
223 class owDS2450(owDevice):
224 def setdefaultConfig(self):
225 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]
227 def convertAll(self):
228 ret=owcom(self.owid,[0x3C,0x0F,0x00],2)
229 if not(crc16([0x3C,0x0F,0x00]+ret)):
233 ret=owcom(self.owid,[0xAA,0x00,0x00],10)
234 if not(crc16([0xAA,0x00,0x00]+ret)):
238 self.raw[i]=ret[2*i]|(ret[2*i+1]<<8);
240 self.values[i]=calcValue(self.config[i*2+1],i,self.raw)
243 class owDS18B20(owDevice):
244 def setdefaultConfig(self):
245 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]
247 def convertAll(self):
248 owcom(self.owid,[0x44],0)
250 ret=owcom(self.owid,[0xBE],9)
254 self.raw[0]=ow_fconvert(ret[0],ret[1]);
255 self.values[0]=calcValue(self.config[0*2+1],0,self.raw)
260 class owDS2438(owDevice):
261 def setdefaultConfig(self):
262 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]
264 def readScratchpad(self,page,recall):
266 owcom(self.owid,[0xB8,page],0)
267 ret=owcom(self.owid,[0xBE,page],9)
273 def setConfigByte(self, cb):
275 owcom(self.owid,[0x4E,0x00,cb],0)
276 sp=self.readScratchpad(0,False)
284 def convertAll(self):
285 owcom(self.owid,[0x44],0)
287 self.setConfigByte(0x08)
288 owcom(self.owid,[0xB4],0)
290 sp=self.readScratchpad(0,True)
293 temp=ow_fconvert(sp[1],sp[2]);
294 VDD=ow_fconvert(sp[3],sp[4]);
295 self.setConfigByte(0x00)
296 owcom(self.owid,[0xB4],0)
298 sp=self.readScratchpad(0,True);
301 I=ow_fconvert(sp[5],sp[6]);
302 VAD=ow_fconvert(sp[3],sp[4]);
308 self.values[i]=calcValue(self.config[i*2+1],i,self.raw)
310 class owDS2423(owDevice):
311 def setdefaultConfig(self):
312 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]
314 def readCounter(self,page):
316 ret=owcom(self.owid,[0xA5,addr&0xFF,addr>>8],11)
317 if not(crc16([0xA5,addr&0xFF,addr>>8]+ret)):
327 def convertAll(self):
329 self.raw[i]=self.readCounter(i+12);
331 self.values[i]=calcValue(self.config[i*2+1],i,self.raw)