add formel 18
[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 if code==18:
86 return V[vn]/8.0;
87 return 0;
88
89
90
91 def owcom(dev,send,rc):
92 res=[]
93 try:
94 f=open("/sys/bus/w1/devices/%s/rw" %(dev),"r+b",0)
95 except IOError:
96 l=subprocess.check_output("rmmod w1_therm",shell=True)
97 f=open("/sys/bus/w1/devices/%s/rw" %(dev),"r+b",0)
98 f.write("".join(map(chr, send)))
99 if (rc!=0):
100 res=map(ord,f.read(rc))
101 f.close()
102 return res
103
104
105 def crc8(arr):
106 lscrc=0x0;
107 for v in arr:
108 bit=1;
109 while bit<256:
110 if (v&bit)==bit:
111 lb=1
112 else:
113 lb=0
114 if (lscrc&1)!=lb:
115 lscrc=(lscrc>>1)^0x8c
116 else:
117 lscrc=(lscrc>>1)
118 bit=bit*2
119 return (lscrc==0)
120
121
122 oddparity = [ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 ]
123
124
125 def crc16(arr):
126 crc16=0
127 for cdata in arr:
128 cdata = (cdata ^ (crc16 & 0xff)) & 0xff;
129 crc16 = crc16>>8;
130 if (oddparity[cdata & 0xf] ^ oddparity[cdata >> 4]):
131 crc16 = crc16 ^ 0xc001;
132 cdata = (cdata << 6)&0xffff;
133 crc16 = crc16 ^ cdata;
134 cdata = (cdata << 1)&0xffff;
135 crc16 = crc16^cdata;
136 #r=crc16==0xB001
137 return (crc16==0xB001)
138
139
140 def ow_fconvert(b1, b2):
141 tsht = b1 | (b2 << 8)
142 if (b2 & 0x080):
143 tsht=-(tsht&0x7FFF)
144 return tsht
145
146
147 def testnr(s):
148 for c in s.lower()[:]:
149 if not((c) in ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','-']):
150 return False
151 return True
152
153 def addid(id,val):
154 for i in range(7):
155 id[i+1]=id[i+1]+val
156 if id[i+1]>254:
157 id[i+1]=id[i+1]-254
158 val=1
159 else:
160 return id
161 return id
162 #
163
164 def owfind(famcodes):
165 l=subprocess.check_output("ls /sys/bus/w1/devices/", shell=True)
166 dl=[]
167 for g in (l.split("\n")):
168 if len(g)>2:
169 if testnr(g[0:2]):
170 if (g[0:2] in famcodes) or len(famcodes)==0:
171 dl.append(g)
172 print g
173 return dl;
174
175
176 class owDevice:
177 raw=[0,0,0,0]
178 values=[0.0,0.0,0.0,0.0]
179 owid=""
180 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]
181 def __init__(self, owid):
182 self.owid = owid
183
184 def setdefaultConfig(self):
185 raise NotImplementedError()
186
187 def readConfig(self):
188 self.config=owcom(self.owid,[0x85],26)
189 print self.config
190 if self.config[0]==0xFF:
191 print("No Deviceconfig. Not a Device form tm3d.de. Set Default");
192 self.setdefaultConfig()
193 else:
194 if self.config[25]==0xFF:
195 if crc8(self.config[0:24]):
196 print("CRC Error reading Deviceconfig. Set Default")
197 self.setdefaultConfig()
198 else:
199 if not(crc16([0x85]+self.config)):
200 print("CRC Error reading Deviceconfig. Set Default")
201 self.setdefaultConfig()
202
203 def convertAll(self):
204 raise NotImplementedError()
205
206 def getChips(self):
207 l=[];
208 for i in range(0,4):
209 l.append(devChip[self.config[i+9]])
210 return l
211
212 def getUnits(self):
213 l=[];
214 for i in range(0,4):
215 l.append(devUnit[self.config[i*2]])
216 return l
217
218 def getProperties(self):
219 l=[];
220 for i in range(0,4):
221 l.append(devInfo[self.config[i*2]])
222 return l
223
224
225 class owDS2450(owDevice):
226 def setdefaultConfig(self):
227 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]
228
229 def convertAll(self):
230 ret=owcom(self.owid,[0x3C,0x0F,0x00],2)
231 if not(crc16([0x3C,0x0F,0x00]+ret)):
232 print("CRC ERROR")
233 return
234 time.sleep(1)
235 ret=owcom(self.owid,[0xAA,0x00,0x00],10)
236 if not(crc16([0xAA,0x00,0x00]+ret)):
237 print("CRC ERROR")
238 return
239 for i in range(0,4):
240 self.raw[i]=ret[2*i]|(ret[2*i+1]<<8);
241 for i in range(0,4):
242 self.values[i]=calcValue(self.config[i*2+1],i,self.raw)
243
244
245 class owDS18B20(owDevice):
246 def setdefaultConfig(self):
247 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]
248
249 def convertAll(self):
250 owcom(self.owid,[0x44],0)
251 time.sleep(1)
252 ret=owcom(self.owid,[0xBE],9)
253 if not(crc8(ret)):
254 print("CRC ERROR")
255 return
256 self.raw[0]=ow_fconvert(ret[0],ret[1]);
257 self.values[0]=calcValue(self.config[0*2+1],0,self.raw)
258 self.values[1]=0;
259 self.values[2]=0;
260 self.values[3]=0;
261
262 class owDS2438(owDevice):
263 def setdefaultConfig(self):
264 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]
265
266 def readScratchpad(self,page,recall):
267 if (recall):
268 owcom(self.owid,[0xB8,page],0)
269 ret=owcom(self.owid,[0xBE,page],9)
270 if not(crc8(ret)):
271 print("CRC ERROR")
272 return []
273 return ret
274
275 def setConfigByte(self, cb):
276 for i in range(3):
277 owcom(self.owid,[0x4E,0x00,cb],0)
278 sp=self.readScratchpad(0,False)
279 if (sp!=[]):
280 if sp[0]==cb:
281 return True
282 return False
283
284
285
286 def convertAll(self):
287 owcom(self.owid,[0x44],0)
288 time.sleep(0.01)
289 self.setConfigByte(0x08)
290 owcom(self.owid,[0xB4],0)
291 time.sleep(0.01)
292 sp=self.readScratchpad(0,True)
293 if sp==[]:
294 return
295 temp=ow_fconvert(sp[1],sp[2]);
296 VDD=ow_fconvert(sp[3],sp[4]);
297 self.setConfigByte(0x00)
298 owcom(self.owid,[0xB4],0)
299 time.sleep(0.01)
300 sp=self.readScratchpad(0,True);
301 if sp==[]:
302 return
303 I=ow_fconvert(sp[5],sp[6]);
304 VAD=ow_fconvert(sp[3],sp[4]);
305 self.raw[0]=temp;
306 self.raw[1]=VDD;
307 self.raw[2]=VAD;
308 self.raw[3]=I;
309 for i in range(0,4):
310 self.values[i]=calcValue(self.config[i*2+1],i,self.raw)
311
312 class owDS2423(owDevice):
313 def setdefaultConfig(self):
314 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]
315
316 def readCounter(self,page):
317 addr=(page<<5)+31
318 ret=owcom(self.owid,[0xA5,addr&0xFF,addr>>8],11)
319 if not(crc16([0xA5,addr&0xFF,addr>>8]+ret)):
320 print("CRC ERROR")
321 return 0
322 c=0
323 for i in range (4):
324 c<<=8;
325 c|=ret[4-i];
326 return c;
327
328
329 def convertAll(self):
330 for i in range(4):
331 self.raw[i]=self.readCounter(i+12);
332 for i in range(0,4):
333 self.values[i]=calcValue(self.config[i*2+1],i,self.raw)
334