배터리: ? %
비거니즘 전시 매뉴얼
\353\260\260\355\204\260\353\246\254 \354\240\204\354\225\225 \354\240\204\353\245\230 \354\235\275\353\212\224 \354\275\224\353\223\234.md
... ...
@@ -0,0 +1,334 @@
1
+ina226.py
2
+
3
+```
4
+#!/usr/bin/env python3
5
+# -*- coding: utf-8 -*-
6
+import time
7
+import math
8
+import ctypes
9
+import sys
10
+
11
+PYTHON_SMBUS_LIB_PRESENT = True
12
+PYTHON_AARDVARK_LIB_PRESENT = False
13
+
14
+try:
15
+ import smbus
16
+except ImportError as e:
17
+ PYTHON_SMBUS_LIB_PRESENT = False
18
+
19
+try:
20
+ import pyaardvark
21
+except ImportError as e:
22
+ PYTHON_AARDVARK_LIB_PRESENT = False
23
+
24
+
25
+
26
+INA226_ADDRESS =(0x40)
27
+
28
+INA226_REG_CONFIG =(0x00)
29
+INA226_REG_SHUNTVOLTAGE =(0x01)
30
+INA226_REG_BUSVOLTAGE =(0x02)
31
+INA226_REG_POWER =(0x03)
32
+INA226_REG_CURRENT =(0x04)
33
+INA226_REG_CALIBRATION =(0x05)
34
+INA226_REG_MASKENABLE =(0x06)
35
+INA226_REG_ALERTLIMIT =(0x07)
36
+
37
+INA226_BIT_SOL =(0x8000)
38
+INA226_BIT_SUL =(0x4000)
39
+INA226_BIT_BOL =(0x2000)
40
+INA226_BIT_BUL =(0x1000)
41
+INA226_BIT_POL =(0x0800)
42
+INA226_BIT_CNVR =(0x0400)
43
+INA226_BIT_AFF =(0x0010)
44
+INA226_BIT_CVRF =(0x0008)
45
+INA226_BIT_OVF =(0x0004)
46
+INA226_BIT_APOL =(0x0002)
47
+INA226_BIT_LEN =(0x0001)
48
+
49
+#enum replacement, but not truly
50
+#now replaced class by dict because it can give me back keys
51
+ina226_averages_t = dict(
52
+ INA226_AVERAGES_1 = 0b000,
53
+ INA226_AVERAGES_4 = 0b001,
54
+ INA226_AVERAGES_16 = 0b010,
55
+ INA226_AVERAGES_64 = 0b011,
56
+ INA226_AVERAGES_128 = 0b100,
57
+ INA226_AVERAGES_256 = 0b101,
58
+ INA226_AVERAGES_512 = 0b110,
59
+ INA226_AVERAGES_1024 = 0b111)
60
+
61
+ina226_busConvTime_t = dict(
62
+ INA226_BUS_CONV_TIME_140US = 0b000,
63
+ INA226_BUS_CONV_TIME_204US = 0b001,
64
+ INA226_BUS_CONV_TIME_332US = 0b010,
65
+ INA226_BUS_CONV_TIME_588US = 0b011,
66
+ INA226_BUS_CONV_TIME_1100US = 0b100,
67
+ INA226_BUS_CONV_TIME_2116US = 0b101,
68
+ INA226_BUS_CONV_TIME_4156US = 0b110,
69
+ INA226_BUS_CONV_TIME_8244US = 0b111)
70
+
71
+ina226_shuntConvTime_t = dict(
72
+ INA226_SHUNT_CONV_TIME_140US = 0b000,
73
+ INA226_SHUNT_CONV_TIME_204US = 0b001,
74
+ INA226_SHUNT_CONV_TIME_332US = 0b010,
75
+ INA226_SHUNT_CONV_TIME_588US = 0b011,
76
+ INA226_SHUNT_CONV_TIME_1100US = 0b100,
77
+ INA226_SHUNT_CONV_TIME_2116US = 0b101,
78
+ INA226_SHUNT_CONV_TIME_4156US = 0b110,
79
+ INA226_SHUNT_CONV_TIME_8244US = 0b111)
80
+
81
+ina226_mode_t = dict(
82
+ INA226_MODE_POWER_DOWN = 0b000,
83
+ INA226_MODE_SHUNT_TRIG = 0b001,
84
+ INA226_MODE_BUS_TRIG = 0b010,
85
+ INA226_MODE_SHUNT_BUS_TRIG = 0b011,
86
+ INA226_MODE_ADC_OFF = 0b100,
87
+ INA226_MODE_SHUNT_CONT = 0b101,
88
+ INA226_MODE_BUS_CONT = 0b110,
89
+ INA226_MODE_SHUNT_BUS_CONT = 0b111)
90
+
91
+# available options are 'AARDVARK','SBC_LINUX_SMBUS'
92
+I2C_DRIVER = 'AARDVARK'
93
+# other I2C options
94
+I2C_DEFAULT_CLK_KHZ = 100
95
+I2C_DEFAULT_BUS_NUMBER = 0
96
+
97
+class ina226:
98
+ def __init__(self,ina226_addr = INA226_ADDRESS, i2c_bus_number=I2C_DEFAULT_BUS_NUMBER, i2c_clk_Khz=I2C_DEFAULT_CLK_KHZ, i2c_driver_type = I2C_DRIVER):
99
+
100
+ self.i2c_bus = smbus.SMBus(i2c_bus_number)
101
+ self.readRegister16 = self.readRegister16_SMBUS
102
+ self.writeRegister16 = self.writeRegister16_SMBUS
103
+ if i2c_clk_Khz != I2C_DEFAULT_CLK_KHZ:
104
+ print 'Python SMBUS linux driver doesn\'t provide I2C CLK Freq Manipulation support yet,'
105
+ print 'So Ignoring i2c_clk_khz param and using default.'
106
+
107
+ self.ina226_address = ina226_addr
108
+ self.vBusMax = 36
109
+ self.vShuntMax = 0.08192
110
+ self.rShunt = 0.1
111
+ self.currentLSB = 0
112
+ self.powerLSB = 0
113
+ self.iMaxPossible = 0
114
+
115
+ #not using with statement related code yet
116
+
117
+ #this causes some issue may be because when exception occurs I am manually calling
118
+ #self.close() and even this function tries to call the same. Need to check.
119
+ #def __del__(self):
120
+ # self.close()
121
+
122
+ def close(self):
123
+ self.i2c_bus.close()
124
+
125
+ def readRegister16_SMBUS(self,register):
126
+ #higher_byte = self.i2c_bus.read_byte_data(self.ina226_address,register)
127
+ #lower_byte = self.i2c_bus.read_byte_data(self.ina226_address,register+1)
128
+ data = self.i2c_bus.read_i2c_block_data(self.ina226_address,register,2)
129
+ higher_byte = data[0]
130
+ lower_byte = data[1]
131
+ #there is still some issue in read which we need to fix, we are not able to print negative current--done--fixed using ctypes int16 return
132
+ word_data = higher_byte << 8 | lower_byte
133
+ #return word_data
134
+ return ctypes.c_int16(word_data).value
135
+
136
+ def writeRegister16_SMBUS(self,register,dataWord):
137
+ higher_byte = (dataWord >> 8) & 0xff
138
+ lower_byte = dataWord & 0xff #truncating the dataword to byte
139
+ self.i2c_bus.write_i2c_block_data(self.ina226_address,register,[higher_byte,lower_byte])
140
+
141
+ def readRegister16_AARDVARK(self,register):
142
+ #higher_byte = self.i2c_bus.read_byte_data(self.ina226_address,register)
143
+ #lower_byte = self.i2c_bus.read_byte_data(self.ina226_address,register+1)
144
+ #data = self.i2c_bus.read_i2c_block_data(self.ina226_address,register,2)
145
+
146
+ register_addr_str = chr(register)
147
+
148
+ byte_char_data = self.i2c_bus.i2c_master_write_read(self.ina226_address,register_addr_str,2)
149
+
150
+ data = [ord(b) for b in byte_char_data]
151
+
152
+ higher_byte = data[0]
153
+ lower_byte = data[1]
154
+ #there is still some issue in read which we need to fix, we are not able to print negative current--done--fixed using ctypes int16 return
155
+ word_data = higher_byte << 8 | lower_byte
156
+ #return word_data
157
+ return ctypes.c_int16(word_data).value
158
+ #if this does not work as expected than we should try to read bytes and they convert into word as in Arduino
159
+ #return self.i2c_bus.read_word_data(self.ina226_address,register)
160
+
161
+ def writeRegister16_AARDVARK(self,register,dataWord):
162
+ higher_byte = (dataWord >> 8) & 0xff
163
+ lower_byte = dataWord & 0xff #truncating the dataword to byte
164
+
165
+ data = (register, higher_byte, lower_byte)
166
+ data = ''.join(chr(c) for c in data)
167
+
168
+ self.i2c_bus.i2c_master_write(self.ina226_address,data)
169
+
170
+ #self.i2c_bus.write_i2c_block_data(self.ina226_address,register,[higher_byte,lower_byte])
171
+
172
+ #doesn't work
173
+ #self.i2c_bus.write_byte_data(self.ina226_address,register,higher_byte)
174
+ #self.i2c_bus.write_byte_data(self.ina226_address,register+1,lower_byte)
175
+ #if this does not work as expected than we should try to read bytes and they convert into word as in Arduino
176
+ #self.i2c_bus.write_word_data(self.ina226_address,register,dataWord)
177
+
178
+ def configure(self,avg = ina226_averages_t['INA226_AVERAGES_1'], busConvTime = ina226_busConvTime_t['INA226_BUS_CONV_TIME_1100US'], shuntConvTime = ina226_shuntConvTime_t['INA226_SHUNT_CONV_TIME_1100US'], mode = ina226_mode_t['INA226_MODE_SHUNT_BUS_CONT']):
179
+ config = 0
180
+ config |= (avg << 9 | busConvTime << 6 | shuntConvTime << 3 | mode)
181
+ self.writeRegister16(INA226_REG_CONFIG, config)
182
+ return True
183
+
184
+ def calibrate(self,rShuntValue = 0.1, iMaxExcepted = 2):
185
+ self.rShunt = rShuntValue
186
+
187
+ self.iMaxPossible = self.vShuntMax / self.rShunt
188
+
189
+ minimumLSB = float(iMaxExcepted) / 32767
190
+
191
+ #print "minimumLSB:"+str(minimumLSB)
192
+
193
+ self.currentLSB = int((minimumLSB * 100000000))
194
+ #print "currentLSB:"+str(self.currentLSB)
195
+ self.currentLSB /= 100000000.0
196
+ self.currentLSB /= 0.0001
197
+ self.currentLSB = math.ceil(self.currentLSB)
198
+ self.currentLSB *= 0.0001
199
+
200
+ self.powerLSB = self.currentLSB * 25;
201
+
202
+
203
+ #print "powerLSB:"+str(self.powerLSB)
204
+ #print "rshunt:"+str(self.rShunt)
205
+
206
+ calibrationValue = int(((0.00512) / (self.currentLSB * self.rShunt))) #if we get error need to convert this to unsigned int 16 bit instead
207
+
208
+ self.writeRegister16(INA226_REG_CALIBRATION, calibrationValue)
209
+
210
+ return True
211
+
212
+ def getAverages(self):
213
+ value = self.readRegister16(INA226_REG_CONFIG)
214
+ value &= 0b0000111000000000
215
+ value >>= 9
216
+ return value
217
+
218
+ def getMaxPossibleCurrent(self):
219
+ return (self.vShuntMax / self.rShunt)
220
+
221
+ def getMaxCurrent(self):
222
+ maxCurrent = (self.currentLSB * 32767)
223
+ maxPossible = self.getMaxPossibleCurrent()
224
+
225
+ if maxCurrent > maxPossible:
226
+ return maxPossible
227
+ else:
228
+ return maxCurrent
229
+
230
+ def getMaxShuntVoltage(self):
231
+ maxVoltage = self.getMaxCurrent() * self.rShunt
232
+ if maxVoltage >= self.vShuntMax:
233
+ return self.vShuntMax
234
+ else:
235
+ return maxVoltage
236
+
237
+ def getMaxPower(self):
238
+ return (self.getMaxCurrent() * self.vBusMax)
239
+
240
+ def readBusPower(self):
241
+ return (self.readRegister16(INA226_REG_POWER) * self.powerLSB)
242
+
243
+ def readShuntCurrent(self):
244
+ return (self.readRegister16(INA226_REG_CURRENT) * self.currentLSB)
245
+
246
+ def readShuntVoltage(self):
247
+ voltage = self.readRegister16(INA226_REG_SHUNTVOLTAGE)
248
+ return (voltage * 0.0000025)
249
+
250
+ def readBusVoltage(self):
251
+ voltage = self.readRegister16(INA226_REG_BUSVOLTAGE)
252
+ return (voltage * 0.00125)
253
+
254
+ def getBusConversionTime(self):
255
+ value = self.readRegister16(INA226_REG_CONFIG)
256
+ value &= 0b0000000111000000
257
+ value >>= 6
258
+ return value
259
+
260
+ def getShuntConversionTime(self):
261
+ value = self.readRegister16(INA226_REG_CONFIG)
262
+ value &= 0b0000000000111000
263
+ value >>= 3
264
+ return value
265
+
266
+ def getMode(self):
267
+ value = self.readRegister16(INA226_REG_CONFIG)
268
+ value &= 0b0000000000000111
269
+ return value
270
+
271
+ def setMaskEnable(self, mask):
272
+ self.writeRegister16(INA226_REG_MASKENABLE, mask)
273
+
274
+ def getMaskEnable(self):
275
+ return self.readRegister16(INA226_REG_MASKENABLE)
276
+
277
+ def enableShuntOverLimitAlert(self):
278
+ self.writeRegister16(INA226_REG_MASKENABLE, INA226_BIT_SOL)
279
+
280
+ def enableBusOverLimitAlert(self):
281
+ self.writeRegister16(INA226_REG_MASKENABLE, INA226_BIT_BOL)
282
+
283
+ def enableBusUnderLimitAlert(self):
284
+ self.writeRegister16(INA226_REG_MASKENABLE, INA226_BIT_BUL)
285
+
286
+ def enableOverPowerLimitAlert(self):
287
+ self.writeRegister16(INA226_REG_MASKENABLE, INA226_BIT_POL)
288
+
289
+ def enableConversionReadyAlert(self):
290
+ self.writeRegister16(INA226_REG_MASKENABLE, INA226_BIT_CNVR)
291
+
292
+ def setBusVoltageLimit(self, voltage):
293
+ value = voltage / 0.00125
294
+ self.writeRegister16(INA226_REG_ALERTLIMIT, value)
295
+
296
+ def setShuntVoltageLimit(self, voltage):
297
+ value = voltage * 25000
298
+ self.writeRegister16(INA226_REG_ALERTLIMIT, value)
299
+
300
+ def setPowerLimit(self, watts):
301
+ value = watts / self.powerLSB
302
+ self.writeRegister16(INA226_REG_ALERTLIMIT, value)
303
+
304
+ def setAlertInvertedPolarity(self, inverted):
305
+ temp = self.getMaskEnable()
306
+
307
+ if (inverted):
308
+ temp |= INA226_BIT_APOL;
309
+ else:
310
+ temp &= ~INA226_BIT_APOL;
311
+ self.setMaskEnable(temp)
312
+
313
+ def setAlertLatch(self, latch):
314
+ temp = self.getMaskEnable()
315
+ if (latch):
316
+ temp |= INA226_BIT_LEN
317
+ else:
318
+ temp &= ~INA226_BIT_LEN
319
+ self.setMaskEnable(temp)
320
+
321
+ def isMathOverflow(self):
322
+ return ((self.getMaskEnable() & INA226_BIT_OVF) == INA226_BIT_OVF)
323
+
324
+ def isAlert(self):
325
+ return ((self.getMaskEnable() & INA226_BIT_AFF) == INA226_BIT_AFF)
326
+
327
+import sys
328
+iSensor = ina226(INA226_ADDRESS,1)
329
+iSensor.configure(avg = ina226_averages_t['INA226_AVERAGES_4'],)
330
+iSensor.calibrate(rShuntValue = 0.02, iMaxExcepted = 2)
331
+time.sleep(1)
332
+batteryPercentage = ((round(iSensor.readBusVoltage(),3)-10.5) / (14.3-10.5)) * 100.0
333
+sys.stdout.write(str(round(iSensor.readShuntCurrent(),3)) +' '+ str(round(iSensor.readBusVoltage(),1)) +' '+ str(round(iSensor.readBusPower(),1))+' ' + str(round(batteryPercentage,1)) +'\n')
334
+```
... ...
\ No newline at end of file

태양광 웹 서버

배터리 남은 용량: %
배터리 전압: V
전기 사용: Watt
서버 시간:
가동 시간:
날씨(구름량):
위치: 위도 37.493423, 경도 126.834054

제로의 예술

바림 (광주광역시 동구 대의동 80-2 3층)
여성을 위한 열린 기술랩 (서울시 중구 을지로 157 대림상가 세운메이커스큐브 대림-동측 306호)

2021 아르코 융복합 예술 페스티벌 《횡단하는 물질의 세계》
2021 ARKO Art & Tech Festival Nothing Makes Itself