Open-source weather station for astronomy

Update code

Changed files
+22 -19
code
+14 -11
code/esp32/main.py
··· 21 DHT22sensor = dht.DHT22(Pin(0)) 22 # MLX90640 Infrared camera 23 MLX90640sensor = MLX90640(i2c) 24 - MLX90640sensor.refresh_rate = RefreshRate.REFRESH_1_HZ 25 ir_frame = init_float_array(768) 26 # MH-RD Rain sensor 27 MHRDsensor = ADC(Pin(1)) ··· 29 MHRDsensor.atten(ADC.ATTN_11DB) 30 # TSL2591 luminosity 31 TSL2591 = tsl2591.TSL2591(i2c=i2c) 32 - TSL2591.gain = tsl2591.GAIN_LOW 33 TSL2591.integration_time = tsl2591.INTEGRATIONTIME_100MS 34 35 def dew_point(tc, rh): ··· 61 62 # Establish connection 63 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 64 - s.bind(('', 80)) 65 s.listen(5) 66 67 oldsec = -1 ··· 90 91 # MLX90640 Infrared camera 92 MLX90640sensor.get_frame(ir_frame) 93 ir_center = cutout_frame(ir_frame, 16, 12, 5, 5) 94 temp_sky = mean(ir_center) 95 # Heuristic to check in real conditions ··· 102 103 # MHRD Rain sensor 104 rain_sens = MHRDsensor.read() 105 - if (rain_sens > 3_200): 106 rain = 0 107 - elif (rain_sens > 3_000): 108 - rain = -(rain - 3_200)/(3_200-3_000) 109 else: 110 rain = 1 111 112 # TSL2591 luminosity 113 - try: 114 - tsl_lux = TSL2591.lux 115 - except RuntimeError: # Luminosity saturation 116 - tsl_lux = -1 117 tsl_ir = TSL2591.infrared 118 tsl_vis = TSL2591.visible 119 tsl_full = TSL2591.full_spectrum ··· 136 # file.write(f"pressure={pressure:.2f} <br />\n") # WeatherWatcher keyword 137 file.write(f"luminosity={tsl_lux:.5f} <br />\n") 138 file.write('</body>\n') 139 - file.write(f"<ir_image>\n{str(ir_frame)}\n</ir_image>\n") 140 file.write('</html>\n') 141 file.close() 142
··· 21 DHT22sensor = dht.DHT22(Pin(0)) 22 # MLX90640 Infrared camera 23 MLX90640sensor = MLX90640(i2c) 24 + MLX90640sensor.refresh_rate = RefreshRate.REFRESH_2_HZ 25 ir_frame = init_float_array(768) 26 # MH-RD Rain sensor 27 MHRDsensor = ADC(Pin(1)) ··· 29 MHRDsensor.atten(ADC.ATTN_11DB) 30 # TSL2591 luminosity 31 TSL2591 = tsl2591.TSL2591(i2c=i2c) 32 + TSL2591.gain = tsl2591.GAIN_HIGH 33 TSL2591.integration_time = tsl2591.INTEGRATIONTIME_100MS 34 35 def dew_point(tc, rh): ··· 61 62 # Establish connection 63 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 64 + try: 65 + s.bind(('', 80)) 66 + except OSError: 67 + continue 68 s.listen(5) 69 70 oldsec = -1 ··· 93 94 # MLX90640 Infrared camera 95 MLX90640sensor.get_frame(ir_frame) 96 + MLX90640sensor.get_frame(ir_frame) # Read twice to solve checkerboard issue 97 ir_center = cutout_frame(ir_frame, 16, 12, 5, 5) 98 temp_sky = mean(ir_center) 99 # Heuristic to check in real conditions ··· 106 107 # MHRD Rain sensor 108 rain_sens = MHRDsensor.read() 109 + if (rain_sens > 3_000): 110 rain = 0 111 + elif (rain_sens > 2_800): 112 + rain = -(rain_sens - 3_000)/(3_000-2_800) 113 else: 114 rain = 1 115 116 # TSL2591 luminosity 117 + tsl_lux = TSL2591.lux_auto_gain 118 tsl_ir = TSL2591.infrared 119 tsl_vis = TSL2591.visible 120 tsl_full = TSL2591.full_spectrum ··· 137 # file.write(f"pressure={pressure:.2f} <br />\n") # WeatherWatcher keyword 138 file.write(f"luminosity={tsl_lux:.5f} <br />\n") 139 file.write('</body>\n') 140 + file.write('<ir_image>\n') 141 + file.write(f"ir_image={str(ir_frame)} <br />\n") 142 + file.write('</ir_image>\n') 143 file.write('</html>\n') 144 file.close() 145
+6 -7
code/esp32/mlx90640.py
··· 5 import struct 6 7 import machine 8 - import typing 9 10 11 def init_float_array(size) -> array.array: ··· 122 self._extract_parameters() 123 124 @property 125 - def serial_number(self) -> typing.List[int]: 126 """3-item tuple of hex values that are unique to each MLX90640""" 127 serial_words = [0, 0, 0] 128 self._i2c_read_words(self.mlx90640_deviceid1, serial_words) ··· 145 value |= control_register[0] & 0xFC7F 146 self._i2c_write_word(0x800D, value) 147 148 - def get_frame(self, framebuf: typing.List[int]) -> None: 149 """Request both 'halves' of a frame from the sensor, merge them 150 and calculate the temperature in C for each of 32x24 pixels. Placed 151 into the 768-element array passed in!""" ··· 214 215 return vdd 216 217 - def _calculate_to(self, emissivity: float, tr: float, result: typing.List[float]) -> None: 218 sub_page = self.mlx90640_frame[833] 219 alpha_corr_r = [0] * 4 220 ir_data_cp = [0, 0] ··· 761 if self._are_pixels_adjacent(broken_pixel, outlier_pixel): 762 raise RuntimeError('Adjacent broken and outlier pixels') 763 764 - def _unique_list_pairs(self, input_list: typing.List[int]) -> typing.Tuple[int, int]: 765 for i, list_value1 in enumerate(input_list): 766 for list_value2 in input_list[i + 1:]: 767 yield list_value1, list_value2 ··· 795 def _i2c_read_words( 796 self, 797 addr: int, 798 - buffer: typing.Union[int, typing.List[int]], 799 *, 800 - end: typing.Optional[int] = None, 801 ) -> None: 802 if end is None: 803 remaining_words = len(buffer)
··· 5 import struct 6 7 import machine 8 9 10 def init_float_array(size) -> array.array: ··· 121 self._extract_parameters() 122 123 @property 124 + def serial_number(self): 125 """3-item tuple of hex values that are unique to each MLX90640""" 126 serial_words = [0, 0, 0] 127 self._i2c_read_words(self.mlx90640_deviceid1, serial_words) ··· 144 value |= control_register[0] & 0xFC7F 145 self._i2c_write_word(0x800D, value) 146 147 + def get_frame(self, framebuf) -> None: 148 """Request both 'halves' of a frame from the sensor, merge them 149 and calculate the temperature in C for each of 32x24 pixels. Placed 150 into the 768-element array passed in!""" ··· 213 214 return vdd 215 216 + def _calculate_to(self, emissivity: float, tr: float, result) -> None: 217 sub_page = self.mlx90640_frame[833] 218 alpha_corr_r = [0] * 4 219 ir_data_cp = [0, 0] ··· 760 if self._are_pixels_adjacent(broken_pixel, outlier_pixel): 761 raise RuntimeError('Adjacent broken and outlier pixels') 762 763 + def _unique_list_pairs(self, input_list): 764 for i, list_value1 in enumerate(input_list): 765 for list_value2 in input_list[i + 1:]: 766 yield list_value1, list_value2 ··· 794 def _i2c_read_words( 795 self, 796 addr: int, 797 + buffer, 798 *, 799 + end = None, 800 ) -> None: 801 if end is None: 802 remaining_words = len(buffer)
+2 -1
code/esp32/test/test_mlx90640.py
··· 4 5 i2c = I2C(0, sda=Pin(22), scl=Pin(23), freq=400000) 6 mlx = MLX90640(i2c) 7 - mlx.refresh_rate = RefreshRate.REFRESH_1_HZ 8 frame = init_float_array(768) 9 while True: 10 mlx.get_frame(frame) 11 print(frame) 12 time.sleep(2)
··· 4 5 i2c = I2C(0, sda=Pin(22), scl=Pin(23), freq=400000) 6 mlx = MLX90640(i2c) 7 + mlx.refresh_rate = RefreshRate.REFRESH_2_HZ 8 frame = init_float_array(768) 9 while True: 10 + mlx.get_frame(frame) 11 mlx.get_frame(frame) 12 print(frame) 13 time.sleep(2)