Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слеваПредыдущая версия
Следующая версия
Предыдущая версия
products:laboratory_iot_c:exp70 [2024/12/17 18:06] – [Эксперимент 70. Графический интерфейс метеостанции] labuser30products:laboratory_iot_c:exp70 [2024/12/17 18:21] (текущий) – [Программный код эксперимента] labuser30
Строка 23: Строка 23:
 ==== Программный код эксперимента ==== ==== Программный код эксперимента ====
  
-<file python Exp70.py[enable_line_numbers="2", start_line_numbers_at="1"]> +<file arduino Exp70.ino[enable_line_numbers="2", start_line_numbers_at="1"]> 
-from machine import Pin, SPI +#include <SPI.h> 
-from tft import TFT_GREEN +#include <Adafruit_ST7735.h>  
-import font +#include "LittleFS_ImageReader.h"  
-import network +#include <ArduinoJson.h> 
-import gc +  
-import time +#define PIN_CS 
-import socket+#define PIN_DC 
 +#define PIN_RST 5 
 +  
 +Adafruit_ST7735 tft = Adafruit_ST7735(PIN_CS,  PIN_DC, PIN_RST); 
 +LittleFS_ImageReader reader;
  
-_init() +void setup() { 
-gc.collect()+  LittleFS.begin()
 +  tft.initR(INITR_BLACKTAB); 
 +  tft.setRotation(2); 
  
-dc  Pin(4, Pin.OUT)  +  String json_string R"({"count": 1, "data": [{"wind_cdir_full": "southeast", "weather": {"code": "804", "icon": "r01d", "description": "Light rain"}, "datetime": "2020-06-15:11", "temp": 24.4, "station": "E8051", "elev_angle": 53.53, "app_temp": 23.8, "state_code": "48", "wind_dir": 137, "last_ob_time": "2020-06-15T10:46:00", "solar_rad": 163.2, "sunrise": "00:43", "slp": 1007, "pod": "d", "vis": 1.5, "pres": 992.8, "wind_cdir": "SE", "wind_spd": 1.34, "ghi": 815.91, "ts": 1592217960, "snow": 0, "uv": 8.64467, "clouds": 100, "city_name": "Moscow", "precip": 2.84211, "timezone": "Europe/Moscow", "country_code": "RU", "dni": 882.12, "dhi": 113.84, "sunset": "18:15", "ob_time": "2020-06-15 10:46", "h_angle": 20, "dewpt": 6.2, "aqi": 48, "lat": 55.7522, "rh": 31, "lon": 37.6156}]})"; 
-cs  = Pin(2, Pin.OUT+  JsonDocument json_doc; 
-rst = Pin(5Pin.OUT)+  deserializeJson(json_docjson_string);
  
 +  String w_city = json_doc["data"][0]["city_name"];
 +  int w_temp = json_doc["data"][0]["temp"];
 +  int w_temp_feels = json_doc["data"][0]["app_temp"];
 +  int w_humidity = json_doc["data"][0]["rh"];
 +  float w_wind = json_doc["data"][0]["wind_spd"];
 +  String w_pod = json_doc["data"][0]["pod"];
 +  int w_code = int(json_doc["data"][0]["weather"]["code"]);
  
-spi SPI(1, baudrate=40000000, polarity=0, phase=0+  String w_pic; 
-tft TFT_GREEN(128, 160, spi, dc, cs, rst, rotate=0+  if (w_code <233) w_pic = "11"; 
-tft.initr(tft.BGR# tft.initr(tft.RGB#Если вместо синего цвета отображается красный, а вместо красного синий+  else if ((w_code >300 && w_code <= 520) || w_code == 522w_pic = "09"; 
 +  else if (w_code >521 && w_code <= 600) w_pic = "10"; 
 +  else if (w_code >601 && w_code <= 622w_pic = "13"; 
 +  else if (w_code >= 623 && w_code <= 751w_pic = "50"; 
 +  else if (w_code == 800w_pic = "01"; 
 +  else if (w_code >= 801 && w_code <=802) w_pic = "02"; 
 +  else if (w_code == 803) w_pic = "03"; 
 +  else if (w_code == 804) w_pic = "04";
  
 +  String w_pic_temp;
 +  if (w_temp > 0) w_pic_temp = "tp";
 +  else w_pic_temp = "tn";
 + 
 +  unsigned int font_color = tft.color565(33, 149, 82);
 +  unsigned int font_color2 = tft.color565(8, 85, 41);
  
-data = {'count': 1, 'data': [{'wind_cdir_full': 'southeast', 'weather': {'code': '804', 'icon': 'r01d', 'description': 'Light rain'}, 'datetime': '2020-06-15:11', 'temp': 24.4, 'station': 'E8051', 'elev_angle': 53.53, 'app_temp': 23.8, 'state_code': '48', 'wind_dir': 137, 'last_ob_time': '2020-06-15T10:46:00', 'solar_rad': 163.2, 'sunrise': '00:43', 'slp': 1007, 'pod': 'd', 'vis': 1.5, 'pres': 992.8, 'wind_cdir': 'SE', 'wind_spd': 1.34, 'ghi': 815.91, 'ts': 1592217960, 'snow': 0, 'uv': 8.64467, 'clouds': 100, 'city_name': 'Moscow', 'precip': 2.84211, 'timezone': 'Europe/Moscow', 'country_code': 'RU', 'dni': 882.12, 'dhi': 113.84, 'sunset': '18:15', 'ob_time': '2020-06-15 10:46', 'h_angle': 20, 'dewpt': 6.2, 'aqi': 48, 'lat': 55.7522, 'rh': 31, 'lon': 37.6156}]}+  tft.fillScreen(ST77XX_WHITE);
  
-wCity = data['data'][0]['city_name'] +  tft.setTextColor(font_color); 
-wTemp = round(data['data'][0]['temp']+  tft.setTextSize(2); 
-wTempFeels = data['data'][0]['app_temp'] +  tft.setCursor(5, 1); 
-wHumidity = data['data'][0]['rh'+  tft.print(w_city);
-wWind = data['data'][0]['wind_spd']+
  
-pod = data['data'][0]['pod']+  reader.drawBMP("/weather/" + w_pic + w_pod + ".bmp", tft, 34, 16); 
 +  reader.drawBMP("/weather/" + w_pic_temp + ".bmp", tft, 5, 70);
  
-wCode = int(data['data'][0]['weather']['code'])+  tft.setTextSize(4)
 +  tft.setCursor(30, 75); 
 +  tft.print(w_temp);
  
-if wCode <= 233: +  tft.setTextColor(font_color2); 
-    wPic = '11' +  tft.setTextSize(1); 
-elif (wCode >= 300 and wCode <= 520or wCode == 522: +  tft.setCursor(5120); 
-    wPic = '09' +  tft.print("Feels" + String(w_temp_feels)); 
-elif wCode in  (521600): +  tft.setCursor(5, 130); 
-    wPic = '10' +  tft.print("Humidity" + String(w_humidity) + "%"); 
-elif wCode >= 601 and wCode <= 622+  tft.setCursor(5140); 
-    wPic = '13' +  tft.print("Wind" + String(w_wind) + "m/s"); 
-elif wCode >= 623 and wCode <= 751+}
-    wPic = '50' +
-elif wCode == 800: +
-    wPic = '01' +
-elif wCode in (801802)+
-    wPic = '02' +
-elif wCode == 803: +
-    wPic = '03' +
-elif wCode == 804+
-    wPic = '04'+
  
-if (wTemp > 0): +void loop() { 
-    wTempPic = 'tp' +}
-else: +
-    wTempPic = 'tn'+
  
-FontColor = tft.rgbcolor(33,149, 82) 
-FontColor2 = tft.rgbcolor(8,85, 41) 
- 
- 
-tft.clear(tft.rgbcolor(255,255, 255))  
- 
- 
-tft.text(1,1,wCity, font.terminalfont, FontColor, 2) 
- 
-tft.draw_bmp(34,16,'/weather/' + wPic + pod + '.bmp') 
-tft.draw_bmp(5,70,'/weather/' + wTempPic + '.bmp') 
- 
-tft.text(30,75, str(wTemp), font.terminalfont, FontColor, 4) 
- 
-tft.text(5,120,"Feels: " + str(wTempFeels), font.terminalfont, FontColor2, 1) 
-tft.text(5,128,"Humidity: " + str(wHumidity) + "%", font.terminalfont, FontColor2, 1) 
-tft.text(5,136,"Wind: " + str(wWind) + "m/s", font.terminalfont, FontColor2, 1) 
 </file> </file>
  
Строка 104: Строка 104:
 Первым делом извлекаем из структуры нужные нам данные. А именно: название города, текущую температуру, влажность, скорость ветра, время суток, код погоды. Разберем по порядку: Первым делом извлекаем из структуры нужные нам данные. А именно: название города, текущую температуру, влажность, скорость ветра, время суток, код погоды. Разберем по порядку:
  
-Название города записываем в переменную wCity  +Название города записываем в переменную w_city  
-<code python[enable_line_numbers="2", start_line_numbers_at="24"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="22"]> 
-wCity data['data'][0]['city_name'+  String w_city json_doc["data"][0]["city_name"];
 </code> </code>
  
-Текущую температуру записываем в переменную wTemp  +Текущую температуру записываем в переменную w_temp  
-<code python[enable_line_numbers="2", start_line_numbers_at="25"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="23"]> 
-wTemp round(data['data'][0]['temp'])+  int w_temp json_doc["data"][0]["temp"];
 </code> </code>
  
-Ощущение температуры записываем в переменную wTempFeels. (например из-за ветра или влажности температура может ощущаться человеком как более низкая, чем есть на самом деле) +Ощущение температуры записываем в переменную w_temp_feels. (например из-за ветра или влажности температура может ощущаться человеком как более низкая, чем есть на самом деле) 
-<code python[enable_line_numbers="2", start_line_numbers_at="26"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="24"]> 
-wTempFeels data['data'][0]['app_temp']+  int w_temp_feels json_doc["data"][0]["app_temp"];
 </code> </code>
  
-Влажность в % записываем в переменную wHumidity  +Влажность в % записываем в переменную w_humidity 
-<code python[enable_line_numbers="2", start_line_numbers_at="27"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="25"]> 
-wHumidity data['data'][0]['rh']+  int w_humidity json_doc["data"][0]["rh"];
 </code> </code>
  
-Скорость ветра в метрах в секунду записываем в переменную wWind  +Скорость ветра в метрах в секунду записываем в переменную w_wind  
-<code python[enable_line_numbers="2", start_line_numbers_at="28"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="26"]> 
-wWind data['data'][0]['wind_spd']+  float w_wind json_doc["data"][0]["wind_spd"];
 </code> </code>
  
-Текущее время суток записываем в переменную pod. Если сейчас день, то в ней будет значение d, а если ночь — n. Эти данные нам понадобятся для выбора правильной иконки погоды. Например, днем мы будем отображать солнышко, а ночью луну. +Текущее время суток записываем в переменную w_pod. Если сейчас день, то в ней будет значение d, а если ночь — n. Эти данные нам понадобятся для выбора правильной иконки погоды. Например, днем мы будем отображать солнышко, а ночью луну. 
-<code python[enable_line_numbers="2", start_line_numbers_at="30"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="27"]> 
-pod data['data'][0]['pod']+  String w_pod json_doc["data"][0]["pod"];
 </code> </code>
  
-Сервис weatherbit.io среди прочих данных о погоде сообщает код текущей погоды. Это коды, которые используются именно этим сервисом. По ним можно понять какую иконку погоды нужно отобразить. [[https://www.weatherbit.io/api/codes|Подробнее о кодах и иконках.]] Код нам будет нужен в виде числа, поэтому сразу преобразуем его в целое число с помощью ''int()'' +Сервис weatherbit.io среди прочих данных о погоде сообщает код текущей погоды. Это коды, которые используются именно этим сервисом. По ним можно понять какую иконку погоды нужно отобразить. [[https://www.weatherbit.io/api/codes|Подробнее о кодах и иконках.]]  
-<code python[enable_line_numbers="2", start_line_numbers_at="32"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="28"]> 
-wCode = int(data['data'][0]['weather']['code'])+  int w_code = int(json_doc["data"][0]["weather"]["code"]);
 </code> </code>
  
-Сервис поддерживает очень большое количество иконок у нас столько нет. У нас всего 18 погодных иконок— 9 дневных и 9 ночных. Поэтому нам нужно настроить соответствие кодов из сервиса нашим иконкам. Например несколько видов дождя, которые обозначаются разными кодами, мы будем отображать одной и той же иконкой. Этот код преобразует коды в 9 иконок: +Сервис поддерживает очень большое количество иконок у нас столько нет. У нас всего 18 погодных иконок — 9 дневных и 9 ночных. Поэтому нам нужно настроить соответствие кодов из сервиса нашим иконкам. Например несколько видов дождя, которые обозначаются разными кодами, мы будем отображать одной и той же иконкой. Этот код преобразует коды в 9 иконок: 
-<code python[enable_line_numbers="2", start_line_numbers_at="34"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="30"]> 
-if wCode <= 233+  String w_pic; 
-    wPic '11' +  if (w_code <= 233) w_pic "11"; 
-elif (wCode >= 300 and wCode <= 520) or wCode == 522+  else if ((w_code >= 300 && w_code <= 520) || w_code == 522) w_pic "09"; 
-    wPic '09' +  else if (w_code >= 521 && w_code <= 600) w_pic "10"; 
-elif wCode in  (521600)+  else if (w_code >= 601 && w_code <= 622) w_pic "13"; 
-    wPic '10' +  else if (w_code >= 623 && w_code <= 751) w_pic "50"; 
-elif wCode >= 601 and wCode <= 622+  else if (w_code == 800) w_pic "01"; 
-    wPic '13' +  else if (w_code >= 801 && w_code <=802) w_pic "02"; 
-elif wCode >= 623 and wCode <= 751+  else if (w_code == 803) w_pic "03"; 
-    wPic '50' +  else if (w_code == 804) w_pic "04";
-elif wCode == 800+
-    wPic '01' +
-elif wCode in (801802)+
-    wPic '02' +
-elif wCode == 803+
-    wPic '03' +
-elif wCode == 804+
-    wPic '04'+
 </code> </code>
  
 Для отображения иконки термометра на дисплее нужно определить положительная сейчас температура или отрицательная. Если температура ниже нуля, то будем отображать "холодный" градусник с синим содержимым, иначе будем отображать "теплый" градусник. Этот код определяет какую иконку градусника нужно будет отобразить: Для отображения иконки термометра на дисплее нужно определить положительная сейчас температура или отрицательная. Если температура ниже нуля, то будем отображать "холодный" градусник с синим содержимым, иначе будем отображать "теплый" градусник. Этот код определяет какую иконку градусника нужно будет отобразить:
  
-<code python[enable_line_numbers="2", start_line_numbers_at="53"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="41"]> 
-if (wTemp > 0)+  String w_pic_temp; 
-    wTempPic 'tp' +  if (w_temp > 0) w_pic_temp "tp"; 
-else+  else w_pic_temp "tn";
-    wTempPic 'tn'+
 </code> </code>
  
 Определяем цвета для шрифтов. Один из них будет использоваться для отображения названия города и температуры, второй для остальной информации. Определяем цвета для шрифтов. Один из них будет использоваться для отображения названия города и температуры, второй для остальной информации.
-<code python[enable_line_numbers="2", start_line_numbers_at="58"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="45"]> 
-FontColor = tft.rgbcolor(33,149, 82) +  unsigned int font_color = tft.color565(33, 149, 82); 
-FontColor2 = tft.rgbcolor(8,85, 41)+  unsigned int font_color2 = tft.color565(8, 85, 41);
 </code> </code>
  
 Закрашиваем весь дисплей белым Закрашиваем весь дисплей белым
-<code python[enable_line_numbers="2", start_line_numbers_at="62"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="48"]> 
-tft.clear(tft.rgbcolor(255,255, 255)+  tft.fillScreen(ST77XX_WHITE);
 </code> </code>
- 
  
 Выводим на дисплей название города Выводим на дисплей название города
-<code python[enable_line_numbers="2", start_line_numbers_at="65"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="50"]> 
-tft.text(1,1,wCity, font.terminalfont, FontColor, 2)+  tft.setTextColor(font_color); 
 +  tft.setTextSize(2); 
 +  tft.setCursor(5, 1); 
 +  tft.print(w_city);
 </code> </code>
  
 Рисуем иконки: иконку погоды и градусник Рисуем иконки: иконку погоды и градусник
-<code python[enable_line_numbers="2", start_line_numbers_at="67"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="55"]> 
-tft.draw_bmp(34,16,'/w/wPic pod '.bmp'+  reader.drawBMP("/weather/w_pic w_pod ".bmp", tft, 34, 16); 
-tft.draw_bmp(5,70,'/w/wTempPic '.bmp')+  reader.drawBMP("/weather/w_pic_temp ".bmp", tft, 5, 70);
 </code> </code>
  
 Выводим текущую температуру Выводим текущую температуру
-<code python[enable_line_numbers="2", start_line_numbers_at="70"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="58"]> 
-tft.text(30,75, str(wTemp), font.terminalfont, FontColor, 4)+  tft.setTextSize(4); 
 +  tft.setCursor(30, 75)
 +  tft.print(w_temp);
 </code> </code>
  
 Выводим дополнительные данные: температура по ощущениям, влажность и скорость ветра Выводим дополнительные данные: температура по ощущениям, влажность и скорость ветра
-<code python[enable_line_numbers="2", start_line_numbers_at="72"]> +<code arduino[enable_line_numbers="2", start_line_numbers_at="62"]> 
-tft.text(5,120,"Feels: " + str(wTempFeels), font.terminalfont, FontColor2, 1+  tft.setTextColor(font_color2); 
-tft.text(5,128,"Humidity: " + str(wHumidity) + "%", font.terminalfont, FontColor2, 1+  tft.setTextSize(1); 
-tft.text(5,136,"Wind: " + str(wWind) + "m/s", font.terminalfont, FontColor2, 1)+  tft.setCursor(5, 120); 
 +  tft.print("Feels: " + String(w_temp_feels)); 
 +  tft.setCursor(5, 130); 
 +  tft.print("Humidity: " + String(w_humidity) + "%"); 
 +  tft.setCursor(5, 140); 
 +  tft.print("Wind: " + String(w_wind) + "m/s");
 </code> </code>