dab4fab82363834efaae68ad314b1dbb18fd69bb
[owPython.git] / owlib.py
1 #!/usr/bin/python
2 # Copyright (c) 2017, Tobias Mueller tm(at)tm3d.de
3 # All rights reserved. 
4
5 # Redistribution and use in source and binary forms, with or without 
6 # modification, are permitted provided that the following conditions are 
7 # met: 
8
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 
14 #    distribution. 
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. 
21
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. 
33
34
35
36
37 import time
38 import subprocess
39 import sys
40 devInfo= ["","temperature","pressure","illuminance","humidity","constant","voltage","current","VOC","counter","CO2","resistance"]
41 devUnit= ["","°C","hPa","lux","%","","V","mA","ppm","","ppm","kOhm"]
42
43 devController=["","Old code","Attiny84A","Attiny44","Atmega328"]
44
45 devChip=["","DS18B20","DS2438","DS2438","DS2438","DS2450","Thermoelement","SHT21","SHT25","DHT22","HIH9021","HDC1080","HIH4030","HIH5030","BMP280","MAX44009","CDM7160","MAX1164/TGS8100","TGS8100","DS2423","intern ADC","SHT35","SHT31"]
46
47
48 def calcValue(code,vn,V):
49         if code==0:
50                 return V[vn]
51         if code==1: 
52                 return V[vn] / 16.0; 
53         if code==2:
54                 return V[vn]/1.6; 
55         if code==3:
56                 return V[vn]*0.2 + 700; 
57         if code==4:
58                 return exp(V[vn] / 160.0); 
59         if code==5:
60                 return V[vn]*62.5 + 55000; 
61         if code==6:
62                 return V[vn] / 256.0; 
63         if code==7:
64                 return ((float(V[2]) / float(V[1]) - 0.16) / 0.0062) / (1.0546 - 0.00216*V[0]/256.0); 
65         if code==8:
66                 return V[vn] / 100.0; 
67         if code==9:
68                 return V[vn] / 65535.0*5.1; 
69         if code==10:
70                 return V[vn] / 65535.0*2.55;
71         if code==11:
72                 return V[vn] / 65535.0*1.1; 
73         if code==12:
74                 return V[vn] / 10.0; 
75         if code==13:
76                 return V[vn];  
77         if code==14:
78                 return (V[vn] - 32767.0) / 100.0;  
79         if code==15:
80                 return exp((V[vn]-32767.0)/1000.0);
81         if code==16:
82                 return V[vn]/32.0;  
83         if code==17:
84                 return V[vn]*0.2441/1000;  
85         return 0;
86
87
88
89 def owcom(dev,send,rc):
90         res=[]
91         try:
92                 f=open("/sys/bus/w1/devices/%s/rw" %(dev),"r+b",0)
93         except IOError:
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)))
97         if (rc!=0):
98                 res=map(ord,f.read(rc))
99         f.close()
100         return res
101                 
102
103 def crc8(arr):
104         lscrc=0x0;
105         for v in arr:
106                 bit=1;
107                 while bit<256:
108                         if (v&bit)==bit:
109                                 lb=1
110                         else:
111                                 lb=0
112                         if (lscrc&1)!=lb:
113                                 lscrc=(lscrc>>1)^0x8c 
114                         else:
115                                 lscrc=(lscrc>>1)
116                         bit=bit*2
117         return (lscrc==0)
118
119
120 oddparity = [ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 ]
121
122
123 def crc16(arr):
124         crc16=0
125         for cdata in arr:
126                 cdata = (cdata ^ (crc16 & 0xff)) & 0xff;
127                 crc16 = crc16>>8;
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;
133                 crc16  = crc16^cdata;
134         #r=crc16==0xB001
135         return (crc16==0xB001)
136
137
138 def ow_fconvert(b1, b2):
139         tsht = b1 | (b2 << 8)
140         if (b2 & 0x080):
141                 tsht=-(tsht&0x7FFF)
142         return tsht
143
144         
145 def testnr(s):
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','-']):
148                         return False
149         return True
150  
151 def addid(id,val):
152         for i in range(7):
153                 id[i+1]=id[i+1]+val
154                 if id[i+1]>254:
155                         id[i+1]=id[i+1]-254
156                         val=1
157                 else:
158                         return id
159         return id
160 #
161
162 def owfind(famcodes):
163         l=subprocess.check_output("ls /sys/bus/w1/devices/", shell=True)
164         dl=[]
165         for g in  (l.split("\n")):
166                 if len(g)>2:
167                         if testnr(g[0:2]):
168                                 if (g[0:2] in famcodes) or len(famcodes)==0:
169                                         dl.append(g)
170                         print g
171         return dl;
172
173
174 class owDevice:
175         raw=[0,0,0,0]
176         values=[0.0,0.0,0.0,0.0]
177         owid=""
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):
180                 self.owid = owid
181     
182         def setdefaultConfig(self):
183                 raise NotImplementedError()
184         
185         def readConfig(self):
186                 self.config=owcom(self.owid,[0x85],26)
187                 print self.config
188                 if self.config[0]==0xFF:
189                         print("No Deviceconfig. Not a Device form tm3d.de. Set Default");
190                         self.setdefaultConfig()
191                 else:
192                         if self.config[25]==0xFF:
193                                 if crc8(self.config[0:24]):
194                                         print("CRC Error reading Deviceconfig. Set Default")
195                                         self.setdefaultConfig()
196                         else:
197                                 if not(crc16([0x85]+self.config)):
198                                         print("CRC Error reading Deviceconfig. Set Default")
199                                         self.setdefaultConfig()
200
201         def convertAll(self):
202                 raise NotImplementedError()
203         
204         def getChips(self):
205                 l=[];
206                 for i in range(0,4):    
207                         l.append(devChip[self.config[i+9]])
208                 return l
209
210         def getUnits(self):
211                 l=[];
212                 for i in range(0,4):    
213                         l.append(devUnit[self.config[i*2]])
214                 return l
215
216         def getProperties(self):
217                 l=[];
218                 for i in range(0,4):    
219                         l.append(devInfo[self.config[i*2]])
220                 return l
221
222
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]
226         
227         def convertAll(self):
228                 ret=owcom(self.owid,[0x3C,0x0F,0x00],2)
229                 if not(crc16([0x3C,0x0F,0x00]+ret)):
230                         print("CRC ERROR")
231                         return
232                 time.sleep(1)
233                 ret=owcom(self.owid,[0xAA,0x00,0x00],10)
234                 if not(crc16([0xAA,0x00,0x00]+ret)):
235                         print("CRC ERROR")
236                         return
237                 for i in range(0,4):
238                         self.raw[i]=ret[2*i]|(ret[2*i+1]<<8);
239                 for i in range(0,4):    
240                         self.values[i]=calcValue(self.config[i*2+1],i,self.raw)
241                         
242         
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]
246         
247         def convertAll(self):
248                 owcom(self.owid,[0x44],0)
249                 time.sleep(1)
250                 ret=owcom(self.owid,[0xBE],9)
251                 if not(crc8(ret)):
252                         print("CRC ERROR")
253                         return
254                 self.raw[0]=ow_fconvert(ret[0],ret[1]);
255                 self.values[0]=calcValue(self.config[0*2+1],0,self.raw)
256                 self.values[1]=0;
257                 self.values[2]=0;
258                 self.values[3]=0;
259
260 class owDS2438(owDevice):
261         def setdefaultConfig(self):
262                 self.config=[1,6, 6,8, 4,7, 6,17, 0,2,3,12,4,0,0,0,0,0,0,0,0,0,0,0]
263
264         def readScratchpad(self,page,recall):
265                 if (recall):
266                         owcom(self.owid,[0xB8,page],0)
267                 ret=owcom(self.owid,[0xBE,page],9)
268                 if not(crc8(ret)):
269                         print("CRC ERROR")
270                         return []
271                 return ret
272
273         def setConfigByte(self, cb):
274                 for i in range(3):
275                         owcom(self.owid,[0x4E,0x00,cb],0)
276                         sp=self.readScratchpad(0,False)
277                         if (sp!=[]):
278                                 if sp[0]==cb:
279                                         return True
280                 return False
281         
282
283                 
284         def convertAll(self):
285                 owcom(self.owid,[0x44],0)
286                 time.sleep(0.01)
287                 self.setConfigByte(0x08)
288                 owcom(self.owid,[0xB4],0)
289                 time.sleep(0.01)
290                 sp=self.readScratchpad(0,True)
291                 if sp==[]:
292                         return
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)
297                 time.sleep(0.01)
298                 sp=self.readScratchpad(0,True);
299                 if sp==[]: 
300                         return
301                 I=ow_fconvert(sp[5],sp[6]);
302                 VAD=ow_fconvert(sp[3],sp[4]);
303                 self.raw[0]=temp;
304                 self.raw[1]=VDD;
305                 self.raw[2]=VAD;
306                 self.raw[3]=I;
307                 for i in range(0,4):    
308                         self.values[i]=calcValue(self.config[i*2+1],i,self.raw)
309
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]
313
314         def readCounter(self,page):
315                 addr=(page<<5)+31
316                 ret=owcom(self.owid,[0xA5,addr&0xFF,addr>>8],11)
317                 if not(crc16([0xA5,addr&0xFF,addr>>8]+ret)):
318                         print("CRC ERROR")
319                         return 0                
320                 c=0
321                 for i in range (4): 
322                         c<<=8;
323                         c|=ret[4-i];
324                 return c;
325         
326         
327         def convertAll(self):
328                 for i in range(4):
329                         self.raw[i]=self.readCounter(i+12);
330                 for i in range(0,4):    
331                         self.values[i]=calcValue(self.config[i*2+1],i,self.raw)
332