Skip to content

Instantly share code, notes, and snippets.

@borrougagnou
Last active July 14, 2026 07:16
Show Gist options
  • Select an option

  • Save borrougagnou/a21613093f323a05167a92212ab1ff7b to your computer and use it in GitHub Desktop.

Select an option

Save borrougagnou/a21613093f323a05167a92212ab1ff7b to your computer and use it in GitHub Desktop.
ND104 Reverse Engineering

⚠️ WIP ⚠️

Reverse Engineering of the keyboard ND104 Chilkey

❤️ Also a big thank to my LLM for helping me put my note sorted, with a title, and be able to create this big documentation
another thank to c00k1e for helping me to discover the chipset name/brand and gadgetoid for posting a photo of the second chipset under the keyboard

Device Overview

The ND104 keyboard appears as two separate USB HID devices:

Device Vendor ID Product ID Purpose
Keyboard 28007 0x6d67 364 0x016c Key input, VIA configuration, RGB, macros, etc.
Screen 21826 0x5542 1 0x0001 LCD display (weather, time, animations, custom images)

It use custom chipset bought by the manufacturer U-BEST (http://you-best.com.tw/).

How to send data

Data can be sent using the hidraw device.

  1. Find the correct hidraw node:
grep -i "5542" /sys/class/hidraw/hidraw*/device/uevent
  1. Write the 32-byte payload (or 64-byte padded) to that device:
cat weather_payload.bin > /dev/hidrawX

or in python:

with open('/dev/hidrawX', 'wb') as f:
    f.write(payload + b'\x00'*32)   # pad to 64 bytes

ND104 Screen Communication - Technical Reference

This section explains how to communicate with the ND104 keyboard's screen (the LCD display) via USB HID on Linux. It covers the device identification, report structure, payload format, checksum.

IMG_20260620_124053

The screen is driven by the following chipset:

The ID Vendor is: 0x5542 and the ID Product is: 0001

Feature Overview

Feature Raw Command (bytes) Raw length Wrapped Notes
Weather update 1c 02 00 00 00 0d 49 01 a5 fe
+ temps + icon
- No (direct) Contains temps +
icon + Uses its own
header and checksum
Time update 1c 03 00 00 00 0f 00 00 a5 38 00 0a 00 01
+ date/time + checksum
11 Yes (wrapped via me()) Weekday is 0-6 (Sun=0)
Reset screen 52 00 01 3 Yes Reboots the screen
Screen menu Down 57 00 01 3 Yes OSD down
Screen menu Up 57 00 02 3 Yes OSD up
Select / OK 57 00 03 3 Yes OSD enter
Back / Return 57 00 04 3 Yes OSD back
Theme / Colors FD 01 + 5 bytes
(bgH, bgL, fgH, fgL, themeID)
7 Yes Colors are RGB565
big-endian + theme ID
Image upload BA 06 AA B0
+ size / data chunks
- (Special) No Complex chunked protocol
Arbitrary HEX send 88 + any hex bytes 1 + N Yes Test mode only
Screen Flip / Switch (not via screen device) - - These are keycodes
sent via the keyboard
HID interface, not the screen.

Firmware Upgrade

The firmware upgrade for the screen can be accessed by pressing Fn + F13 for few second
and a DTU interface will appear:

iy8r7vm

the DFU upgrade mode of the LCD screen exit after 3 minutes of no operation.


1. HID Report Descriptor (from lsusb -v)

When you run sudo lsusb -v -d 5542:0001, the descriptor shows:

Interface Descriptor:
  bInterfaceClass         3 Human Interface Device
  bInterfaceSubClass      0
  bInterfaceProtocol      0
  HID Device Descriptor:
    bcdHID               1.10
    bNumDescriptors       1
    bDescriptorType      34 Report
    wDescriptorLength    34

The raw report descriptor (parsed) is:

06 60 FF 09 61 A1 01 09 62 15 00 26 FF 00 95 40 75 08 81 02 09 03 15 00 26 FF 00 95 40 75 08 91 02 C0

This tells us:

  • Usage Page: Vendor-defined (0xFF60)
  • Collection: Application
  • Input report: 64 bytes (0x40 = 64) : this is what the screen sends to the host.
  • Output report: 64 bytes : this is what the host sends to the screen.

No Report ID is defined, All sendReport() calls use Report ID 0 : the first byte of the report is the command/opcode.


2. The 64-byte HID Report vs. 32-byte Payload

Even though the USB descriptor specifies a 64-byte output report, the screen's firmware only reads the first 32 bytes. The remaining 32 bytes are ignored (they can be any value, but typically zero-filled).

  • 64-byte HID report: The complete packet that must be sent to the device. The USB HID layer expects exactly this size.
  • 32-byte payload: The meaningful part of the report, which contains the actual data (weather, time, etc.).

When you write to /dev/hidraw, the kernel automatically pads your data to the report size (64 bytes) if you write less. Therefore, you can safely send a 32-byte array, the kernel will append 32 zeros.


3. Checksum Usage and Computation

The checksum is a single byte that validate the integrity of data packets.
It's used on a lot of software and other thing to prevents a corruption or a falsification.

Two types appear:

  • 8-bit checksum : for weather (different algorithm) and for time (bitwise-NOT sum).
  • 16-bit CRC : used in the generic wrapper (bytes 6-7) and also in the time packet.

Algorithms are detailed in the relevant sections below.


4. Payload Structure : Where It Comes From

The payload format was reverse-engineered with different tools and method.

The header (0x1c 0x02 ...) are fixed magic + command signature, and the remaining bytes carry the actual data.


4.1 Weather Payload (32 bytes)

This is a direct 32-byte payload; no wrapper is used.

Offsets and Meaning

Offset (hex) Length Description Example
0x00-0x09 10 Fixed header 1c 02 00 00 00 0d 49 01 a5 fe
0x0A (10) 1 Reserved (always 0x00) 00
0x0B (11) 1 Always 0x08 (maybe a flag) 08
0x0C (12) 1 Reserved (always 0x00) 00
0x0D (13) 1 Weather icon index (0-8) 02
0x0E-0x0F 2 Current temperature (signed, °C × 10, big-endian) 01 0e (270 --> 27.0°C)
0x10-0x11 2 Max temperature (same encoding) 01 26 (294 --> 29.4°C)
0x12-0x13 2 Min temperature (same encoding) 00 ed (237 --> 23.7°C)
0x14 (20) 1 8-bit checksum (see below) d4
0x15-0x1F 11 Zero padding 00 ...

Temperatures

Temperatures are stored as signed 16-bit integers (big-endian) multiplied by 10.
For negative values, use two's complement (e.g., 0x8000 + abs(value)). The official code uses the formula:

If temperature is negative, store as `32768 + abs(temp)` (which is the same as signed 16-bit representation).
  Example: -5.2°C --> -52 --> `0xFFCC` (big-endian: `FF CC`).

Weather Icon Index Mapping

Index Weather Condition
0 Sunny / Clear
1 Partly cloudy
2 Cloudy
3 Overcast
4 Rain / Drizzle
5 Snow / Sleet
6 Thunderstorm
7 Mist / Fog
8 (other / unknown)

Weather Checksum Computation

The checksum ensures that the data sent to the screen is not corrupted. The screen will ignore the packet if the checksum is wrong.

Algorithm:

  1. Sum all bytes from offset 0x0A to 0x13 (10 bytes). Allow the sum to overflow beyond 8 bits (we only care about the lowest 8 bits (i.e., sum & 0xFF)).
  2. Take the two's complement of that 8-bit sum. This is equivalent to (0x01 - sum) & 0xFF.
  3. Store this value at offset 0x14.

Why two's complement? Because when the screen re-computes the sum of the same bytes plus the checksum, the result will be exactly 0x01 (or 0x00? Actually it will be 0x01 if we use 0x01 - sum).

In practice:

sum_bytes = sum(payload[0x0A:0x14]) & 0xFF
payload[0x14] = (0x01 - sum_bytes) & 0xFF

Example (Python)

import struct

def build_weather_payload(temp_c, max_temp_c, min_temp_c, icon_index):
    payload = bytearray(32)
    header = bytes.fromhex("1c 02 00 00 00 0d 49 01 a5 fe")
    payload[0:10] = header
    payload[0x0A] = 0x00
    payload[0x0B] = 0x08
    payload[0x0C] = 0x00
    payload[0x0D] = icon_index

    def store_temp(value, offset):
        temp_int = int(round(value * 10))
        packed = struct.pack('>h', temp_int)   # signed 16-bit big-endian
        payload[offset] = packed[0]
        payload[offset+1] = packed[1]

    store_temp(temp_c, 0x0E)
    store_temp(max_temp_c, 0x10)
    store_temp(min_temp_c, 0x12)

    # Checksum
    sum_bytes = sum(payload[0x0A:0x14]) & 0xFF
    payload[0x14] = (0x01 - sum_bytes) & 0xFF

    # rest already zero
    return payload

4.2 Time Payload (32 bytes)

The payload structure is different from the weather one. Also no wrapper used, but note that the 16-bit CRC is computed for bytes 0x06-0x07.

Offsets and Meaning

Offset (hex) Length Description
0x00 1 0x1c
0x01 1 0x03
0x02-0x04 3 Reserved (0x00)
0x05 1 Command (0x0f)
0x06-0x07 2 16-bit CRC (computed over the whole 32-byte payload, with checksum bytes temporarily 0)
0x08 1 0xa5
0x09 1 0x38
0x0A 1 0x00
0x0B 1 0x0a
0x0C 1 0x00
0x0D 1 0x01
0x0E-0x0F 2 Year (big-endian, e.g., 2026 -> 0x07 0xEA) Actually the code is using the full 16-bit for year.
0x10 1 Month (1-12)
0x11 1 Day (1-31)
0x12 1 Hour (0-23)
0x13 1 Minute (0-59)
0x14 1 Second (0-59)
0x15 1 Weekday (0-6, where 0 = Sunday)
0x16 1 8-bit Checksum (see below)
0x17-0x1F 9 Zero padding

16-bit CRC (bytes 0x06-0x07)

It is a CRC-16/CCITT-FALSE with:

  • Polynomial: 0x1021
  • Initial: 0xFFFF
  • No final XOR

The CRC is computed over the entire 32-byte payload (with bytes 0x06-0x07 set to 0x00 temporarily) and stored in big-endian order.

def crc16_ccitt(data):
    crc = 0xFFFF
    for b in data:
        crc ^= (b << 8)
        for _ in range(8):
            if crc & 0x8000:
                crc = (crc << 1) ^ 0x1021   # CCITT polynomial
            else:
                crc <<= 1
            crc &= 0xFFFF
    return crc

In practice, the screen often accepts the time packet even if bytes 0x06-0x07 are left as 0x00. However, for full compatibility, you should compute the CRC.

Time 8-bit Checksum Computation (byte 0x16)

Algorithm:

  1. Sum all bytes from offset 0x09 to 0x15 (13 bytes). Allow overflow.
  2. Take the bitwise NOT (XOR with 0xFF) of the 8-bit sum. This is equivalent to (0xFF - sum) & 0xFF.
  3. Store this value at offset 0x16.

Why bitwise NOT? Because when the screen adds up the same bytes plus the checksum, the result will be 0xFF (all ones), which can be checked.

In practice:

uint8_t sum = 0;
for (int i = 0x09; i <= 0x15; i++) sum += payload[i];
payload[0x16] = (0xFF - sum) & 0xFF;   # or sum_bytes ^ 0xFF

Example (Python)

import datetime

def build_time_payload():
    now = datetime.datetime.now()
    # Convert weekday: Python's weekday() Monday=0 --> getDay() Sunday=0
    weekday_getday = (now.weekday() + 1) % 7

    payload = bytearray(32)
    payload[0] = 0x1c
    payload[1] = 0x03
    payload[2:5] = bytes([0,0,0])
    payload[5] = 0x0f
    payload[6:8] = bytes([0,0])          # will be overwritten by CRC
    payload[8] = 0xa5
    payload[9] = 0x38
    payload[10] = 0x00
    payload[11] = 0x0a
    payload[12] = 0x00
    payload[13] = 0x01
    payload[14] = (now.year >> 8) & 0xFF
    payload[15] = now.year & 0xFF
    payload[16] = now.month
    payload[17] = now.day
    payload[18] = now.hour
    payload[19] = now.minute
    payload[20] = now.second
    payload[21] = weekday_getday

    # 8-bit checksum
    sum8 = sum(payload[0x09:0x16]) & 0xFF
    payload[0x16] = (0xFF - sum8) & 0xFF

    # 16-bit CRC (set bytes 0x06-0x07 to 0 before computing)
    crc = crc16_ccitt(payload)
    payload[6] = (crc >> 8) & 0xFF
    payload[7] = crc & 0xFF

    return payload

4.3 Image Upload (PNG / JPG / GIF)

The screen can display custom images (PNG, JPG, or GIF) with a resolution of 320×172 pixels.

The upload uses a multi-packet chunked protocol with report header BA 06 AA B0.

This protocol is not wrapped in the generic 1C 02 wrapper : it is sent directly as 64-byte HID reports.

Important

  • The screen expects the image to be exactly 320×172. If the dimensions are different, the image may be distorted or rejected.
  • GIF files must have < 60 frames and size < 2 MB, the web interface extracts each frame and sends them individually (since GIFs are animated). The protocol for GIFs is more complex and involves sending frame delays.
  • The chunk size of 60 bytes is derived from the web code (the packets are 64 bytes total, with 4 bytes header). You may experiment with larger chunks if the screen supports it, but 60 is safe.

Protocol Overview

Header Packet:

This packet announces the total size of the image data and starts the transfer.

Offset Length Description
0x00 4 Fixed magic: BA 06 AA B0
0x04 4 Total size of the image data (bytes) : big-endian
0x08 56 (Unused, set to 0)

eg: For a 100-byte image, the first packet would start with BA 06 AA B0 00 00 00 64 followed by zeros.

Data Packets:

After the header, the image data is split into chunks and sent in subsequent packets.
Each packet has the same header BA 06 AA B0 followed by a chunk of the data.

Offset Length Description
0x00 4 Fixed magic: BA 06 AA B0
0x04 60 Data chunk (up to 60 bytes) : the rest is zero-padded

(The report size is 64 bytes, so the chunk can be up to 60 bytes of data.)

  • The last packet may contain fewer than 60 bytes; the remaining bytes are zero-filled.
  • The screen expects the data in the same format as the original file (e.g., JPEG bytes, PNG bytes, or GIF frames).

Finalisation:

After all data packets have been sent, the screen is notified that the transfer is complete.
A final packet (or a separate command) may be required to apply the image.

In the web interface, after the image data transfer, the following sequence is sent (this appears to be a finalisation command).

15 0A 3F 01 01

followed by a reset of some state. This signals the screen to display the uploaded image.

Image Checksum/CRC Computation

You expect a checksum for this one ??? You can cry !!! There's no checksum ! xD
The screen relies on the correct number of bytes and the finalisation command to validate the transfer.
If the data is corrupted, the image will not display correctly.

Example (Python) : Sending a JPEG Image

The following example reads a JPEG file, splits it into chunks, and sends it to the screen.

def send_image(filepath):
    # Read the image data
    with open(filepath, 'rb') as f:
        img_data = f.read()
    total_size = len(img_data)

    # 1. Send header packet
    header = bytearray(64)
    header[0:4] = bytes([0xBA, 0x06, 0xAA, 0xB0])
    header[4:8] = total_size.to_bytes(4, 'big')
    # (rest already zero)
    with open('/dev/hidrawX', 'wb') as hid:
        hid.write(header)

    # 2. Send data packets
    chunk_size = 60
    for i in range(0, total_size, chunk_size):
        packet = bytearray(64)
        packet[0:4] = bytes([0xBA, 0x06, 0xAA, 0xB0])
        chunk = img_data[i:i+chunk_size]
        packet[4:4+len(chunk)] = chunk
        hid.write(packet)

    # 3. Finalisation command (optional but required)
    final = bytearray(64)
    final[0:4] = bytes([0x15, 0x0A, 0x3F, 0x01, 0x01])   # actual command from web code
    hid.write(final)

4.4 Wrapped Command (For theme/Menu control, ...)

For commands like reset, navigation, theme, and debug, the raw command bytes must be wrapped in a "specific 32-byte format" before sending.

Wrapper Structure

The wrapper is built as follows:

Offset Length Value / Description
0x00 1 0x1c
0x01 1 0x02
0x02-0x04 3 0x00 0x00 0x00
0x05 1 Z + 5 where Z = number of bytes in the raw command (the length field)
0x06-0x07 2 16-bit CRC over the entire 32-byte payload, with checksum bytes set to 0)
0x08 1 0xa5
0x09 1 Y[0] : First byte of raw command
0x0A 1 0x00
0x0B 1 Z (raw command length)
0x0C 1 Y[1] : (if Z > 1)
0x0D 1 Y[2] : (if Z > 2)
... ... ...
0x0C + Z - 1 1 Y[Z-1] : Last byte of raw command
0x0C + Z 1 8-bit checksum = (0xFF - sum(0x09..0x1F)) & 0xFF
0x0C + Z + 1 ... 0x1F - Zero-padded to 32 bytes

Y = This is the raw command (see the Feature Overview)
Z = The length field (number of bytes in the raw command)

Note

The 16-bit CRC (bytes 0x06-0x07) is the same as the one used for the time packet.
Compute it over the entire 32-byte > payload (with bytes 0x06-0x07 set to 0 and the 8-bit checksum set to 0 temporarily)

Example (Python) : Building the "Up" Command (57 00 02)

  • Raw command: Y = [0x57, 0x00, 0x02], so Z = 3.
  • Length field at byte 5: Z + 5 = 8 --> hex:0x08.
  • The 32-byte payload (with placeholder for CRC and checksum):
Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ...
Value: 1c 02 00 00 00 08
(Z)
00
(16bit
CRC)
00
(16bit
CRC)
a5 57 00 03 00 02 00(8b
chk)
00 ...

(with 0x06-0x07 set to 0 and 0x0E temporarily 0)

  • Compute 16-bit CRC over the whole array with the information provided earlier
  • Compute 8-bit checksum over bytes 0x09->0x1F (excluding 0x0E initially) and place the result at 0x0E

#TODO UNFINISHED

4.4.1 Theme Payload

#TODO


4.4.2 Other Wrapped command

#TODO


1.4.3 Debug

Warning

This feature is primarily for debugging !
the screen may not respond or may behave unpredictably if you send invalid commands.

I discovered this debug option on the code, but I don't know how to use it/enable it...
It's only use is if you want send raw bytes to the screen...

The raw command for this feature is:

88 XX YY ZZ ...

where XX YY ZZ ... are the hex bytes you want to send.

Wrapping

The raw command is wrapped using the generic wrapper described in 4.4 Wrapped Command
The raw command length is Z = 1 + N, where N is the number of arbitrary hex bytes.

Checksum

The generic wrapper's checksum (8-bit and 16-bit) are used : no additional checksum is added for the 88 command itself.

Example

Suppose you want to send the raw bytes 01 02 03 to the screen for testing. The raw command becomes 88 01 02 03 (Z = 4). You would then use the send_wrapped() function with this raw command.

raw = bytes([0x88, 0x01, 0x02, 0x03])
send_wrapped(raw)

5. Screen Flip / Switch Layout (via Keyboard Keycodes)

Note

These functions are not sent to the screen device; they are keyboard HID keycodes that the keyboard firmware interprets as screen control actions.
They can be sent as normal key press reports through the keyboard interface.

Function Keycode (decimal) Hex
LCD_TG (toggle) 32270 0x7E0E
LCD_UP 32271 0x7E0F
LCD_DN 32272 0x7E10
LCD_RETURN 32278 0x7E16
LCD_ENTER 32279 0x7E17
LCDUP_TOGG 32280 0x7E18
LcdCalc 32289 0x7E21
LcdReset 32290 0x7E22

To send these, you need to send a keyboard HID report (covered below in the Keyboard part).


ND104 Keyboard Communication - Technical Reference

This section covers the keyboard itself and all operations you can do with

51814FB2-3C59-4888-9DC2-0746881D876D

The UB32VF105B chipset is a WCH (Nanjing Qinheng) CH585 (https://www.wch-ic.com/downloads/CH585DS1_PDF.html).

It's a multi-mode wireless MCU/SoC based on the QingKe V3C core, supporting BLE 5.0 and a high-performance custom 2.4GHz protocol using RISC-V (https://www.wch-ic.com/download/file?id=204 page 21)

The ID Vendor is: 6d67 and the ID Product is: 016c

The keyboard exposes 6 HID interfaces:

Interface Use
0 Standard keyboard (boot protocol) : handles key presses.
1 Vendor-specific (usage page 0xFF31, usage 0x0074) : used for VIA (dynamic keymap configuration) and keymap storage.
2 Vendor-specific (usage page 0xFF59) : RGB lighting control (based on usage page 0xFF59).
3 Vendor-specific : handle macro recording and other configuration.
4 Consumer control : handles media keys (play, volume, etc.).
5 Vendor-specific : firmware updates and debugging.

Note

None of these interfaces are used for the screen : the screen is a completely separate device.

Feature Opcode (byte0) Byte Layout (bytes 1‑5) Notes
Set Keymap 0x05 (5) [layer, row, col, keycode_high, keycode_low] layer = 0-5; row = 0-7; col = 0-15; keycode is a 16-bit USB HID usage ID (e.g. 0x04 = A).
Set Knob Action 0x15 (21) [layer, 0, knob_index, keycode_high, keycode_low] knob_index = 0 : turn left/Counter-Clockwise)
knob_index = 1 : turn right/Clockwise.
Knob press is set via normal keymap (row 6, col 9).
RGB - Brightness 0x07 (7) [3, 1, value, 0, 0] value = 0-255. Byte1=3 for keyboard RGB.
RGB - Effect Mode 0x07 (7) [3, 2, effect_id, 0, 0] effect_id = 0-44 (see UI list for exact mapping).
RGB - Effect Speed 0x07 (7) [3, 3, speed, 0, 0] speed = 0-255.
RGB - Color 0x07 (7) [3, 4, hue, sat, 0] hue = 0-255, sat = 0-255 (converted from HSL/HSV).
Commit RGB 0x09 (9) [3, 0, 0, 0, 0] Saves RGB settings to EEPROM.
Macro - Start Recording 0x0D (13) None Sending [13] starts recording key events.
Macro - Stop Recording 0x10 (16) None Sending [16] starts recording key events.
Macro - Upload Data 0x0F (15) #TODO LATER - COMPLEX Used to upload macro definitions after recording.
Debounce / USB Rate 0x07 (7) [0, 4, sub_sub, value, 0] Byte1=0 for keyboard tools. sub_sub: 0=USB rate (1-8 KHz), 1=debounce speed (1-200 ms), 2=debounce mode (0=none,1=send-then-debounce,2=debounce-then-send).
Commit Debounce 0x09 (9) [0, 0, 0, 0, 0] Saves debounce settings.
Enter DFU (Firmware Update) 0x13 (19) [2, 0, 0, 0, 0, 48, 210] 8-byte report. After sending, the device restarts in DFU mode.

Firmware Upgrade

The keyboard is a fully QMK compatible device. To access at the firmware flashing mode you need to hold down both shift keys and press B

When the mode is enabled, the keyboard will not move the RGB anymore and keys will not repond.

the DFU upgrade mode of the keyboard exit after 3 minutes of no operation.


#TODO BIG TODO !!!

The Weather plugin is a NodeJS Application packaged with pkg (Vercel) to V8 Bytecode

To obtain the location of the user, they send request formated like this:

http://ip-api.com/json/?fields=status,message,city,lat,lon

compared to the weather on the website who use the "location service of the web browser"

and same as the website, they use:

https://weather.meletrix.cn/v1/forecast.json?q=<lat>,<lon>

#eg for New York:
https://weather.meletrix.cn/v1/forecast.json?q=40.741,-73.989

to obtain the weather information.


EDIT: I also discovered the website support some country as argument:

https://weather.meletrix.cn/v1/forecast.json?q="tokyo"
https://weather.meletrix.cn/v1/forecast.json?q="delhi"
https://weather.meletrix.cn/v1/forecast.json?q="paris"
https://weather.meletrix.cn/v1/forecast.json?q="washington"

The default one, when something is invalid eg, like this:

https://weather.meletrix.cn/v1/forecast.json?q=%22latitude&longitude%22

is this location:

{
  "location": {
    "name": "Latitude",
    "region": "Jiangxi",
    "country": "Chine",
    "lat": 24.7883,
    "lon": 114.7869,
    "tz_id": "Asia/Shanghai",
    "localtime_epoch": 1784010214,
    "localtime": "2026-07-14 14:23"
  },
  "current": {
    "last_updated_epoch": 1784008800,
    "last_updated": "2026-07-14 14:00",
    "temp_c": 30.7,
    "temp_f": 87.2,
    "is_day": 1,
    "condition": {
      "text": "Patchy rain nearby",
      "icon": "//cdn.weatherapi.com/weather/64x64/day/176.png",
      "code": 1063
    },
    "wind_mph": 13.4,
    "wind_kph": 21.6,
    "wind_degree": 130,
    "wind_dir": "SE",
    "pressure_mb": 1003.0,
    "pressure_in": 29.62,
    "precip_mm": 0.23,
    "precip_in": 0.01,
    "humidity": 66,
    "cloud": 76,
    "feelslike_c": 35.6,
    "feelslike_f": 96.1,
    "windchill_c": 30.7,
    "windchill_f": 87.2,
    "heatindex_c": 35.6,
    "heatindex_f": 96.1,
    "dewpoint_c": 23.5,
    "dewpoint_f": 74.3,
    "vis_km": 9.0,
    "vis_miles": 5.0,
    "uv": 8.1,
    "gust_mph": 18.6,
    "gust_kph": 30.0,
    "will_it_rain": 0,
    "chance_of_rain": 25,
    "will_it_snow": 0,
    "chance_of_snow": 0,
    "short_rad": 715.63,
    "diff_rad": 229.61,
    "dni": 0.0,
    "gti": 0.0
  },
  "forecast": {
    "forecastday": [
      {
        "date": "2026-07-14",
        "date_epoch": 1783987200,
        "day": {
          "maxtemp_c": 32.2,
          "maxtemp_f": 90.0,
          "mintemp_c": 23.6,
          "mintemp_f": 74.5,
          "avgtemp_c": 26.6,
          "avgtemp_f": 79.9,
          "maxwind_mph": 13.4,
          "maxwind_kph": 21.6,
          "totalprecip_mm": 3.38,
          "totalprecip_in": 0.13,
          "totalsnow_cm": 0.0,
          "avgvis_km": 9.2,
          "avgvis_miles": 5.0,
          "avghumidity": 82,
          "daily_will_it_rain": 1,
          "daily_chance_of_rain": 73,
          "daily_will_it_snow": 0,
          "daily_chance_of_snow": 0,
          "condition": {
            "text": "Patchy rain nearby",
            "icon": "//cdn.weatherapi.com/weather/64x64/day/176.png",
            "code": 1063
          },
          "uv": 10.8
        },
        "astro": {
          "sunrise": "05:40 AM",
          "sunset": "07:12 PM",
          "moonrise": "04:44 AM",
          "moonset": "07:06 PM",
          "moon_phase": "New Moon",
          "moon_illumination": 1,
          "is_moon_up": 1,
          "is_sun_up": 1
        },
        "hour": [
          {
            "time_epoch": 1783958400,
            "time": "2026-07-14 00:00",
            "temp_c": 24.6,
            "temp_f": 76.3,
            "is_day": 0,
            "condition": {
              "text": "Partly Cloudy",
              "icon": "//cdn.weatherapi.com/weather/64x64/night/116.png",
              "code": 1003
            },
            "wind_mph": 3.1,
            "wind_kph": 5.0,
            "wind_degree": 147,
            "wind_dir": "SSE",
            "pressure_mb": 1004.0,
            "pressure_in": 29.66,
            "precip_mm": 0.0,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 92,
            "cloud": 25,
            "feelslike_c": 19.6,
            "feelslike_f": 67.3,
            "windchill_c": 24.6,
            "windchill_f": 76.3,
            "heatindex_c": 27.3,
            "heatindex_f": 81.1,
            "dewpoint_c": 23.2,
            "dewpoint_f": 73.7,
            "will_it_rain": 0,
            "chance_of_rain": 16,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 6.3,
            "gust_kph": 10.2,
            "uv": 0,
            "short_rad": 0,
            "diff_rad": 0,
            "dni": 0,
            "gti": 0
          },
          {
            "time_epoch": 1783962000,
            "time": "2026-07-14 01:00",
            "temp_c": 24.4,
            "temp_f": 75.8,
            "is_day": 0,
            "condition": {
              "text": "Partly Cloudy",
              "icon": "//cdn.weatherapi.com/weather/64x64/night/116.png",
              "code": 1003
            },
            "wind_mph": 3.4,
            "wind_kph": 5.4,
            "wind_degree": 138,
            "wind_dir": "SE",
            "pressure_mb": 1004.0,
            "pressure_in": 29.66,
            "precip_mm": 0.0,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 92,
            "cloud": 47,
            "feelslike_c": 19.3,
            "feelslike_f": 66.7,
            "windchill_c": 24.4,
            "windchill_f": 75.8,
            "heatindex_c": 26.9,
            "heatindex_f": 80.5,
            "dewpoint_c": 23.0,
            "dewpoint_f": 73.5,
            "will_it_rain": 0,
            "chance_of_rain": 20,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 6.6,
            "gust_kph": 10.6,
            "uv": 0,
            "short_rad": 0,
            "diff_rad": 0,
            "dni": 0,
            "gti": 0
          },
          {
            "time_epoch": 1783965600,
            "time": "2026-07-14 02:00",
            "temp_c": 24.1,
            "temp_f": 75.4,
            "is_day": 0,
            "condition": {
              "text": "Partly Cloudy",
              "icon": "//cdn.weatherapi.com/weather/64x64/night/116.png",
              "code": 1003
            },
            "wind_mph": 2.9,
            "wind_kph": 4.7,
            "wind_degree": 127,
            "wind_dir": "SE",
            "pressure_mb": 1004.0,
            "pressure_in": 29.66,
            "precip_mm": 0.0,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 93,
            "cloud": 48,
            "feelslike_c": 19.2,
            "feelslike_f": 66.6,
            "windchill_c": 24.1,
            "windchill_f": 75.4,
            "heatindex_c": 26.6,
            "heatindex_f": 79.9,
            "dewpoint_c": 22.9,
            "dewpoint_f": 73.2,
            "will_it_rain": 0,
            "chance_of_rain": 20,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 5.6,
            "gust_kph": 9.1,
            "uv": 0,
            "short_rad": 0,
            "diff_rad": 0,
            "dni": 0,
            "gti": 0
          },
          {
            "time_epoch": 1783969200,
            "time": "2026-07-14 03:00",
            "temp_c": 24.0,
            "temp_f": 75.2,
            "is_day": 0,
            "condition": {
              "text": "Partly Cloudy",
              "icon": "//cdn.weatherapi.com/weather/64x64/night/116.png",
              "code": 1003
            },
            "wind_mph": 3.4,
            "wind_kph": 5.4,
            "wind_degree": 136,
            "wind_dir": "SE",
            "pressure_mb": 1004.0,
            "pressure_in": 29.65,
            "precip_mm": 0.0,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 93,
            "cloud": 55,
            "feelslike_c": 19.0,
            "feelslike_f": 66.2,
            "windchill_c": 24.0,
            "windchill_f": 75.2,
            "heatindex_c": 26.5,
            "heatindex_f": 79.7,
            "dewpoint_c": 22.9,
            "dewpoint_f": 73.2,
            "will_it_rain": 0,
            "chance_of_rain": 22,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 6.3,
            "gust_kph": 10.1,
            "uv": 0,
            "short_rad": 0,
            "diff_rad": 0,
            "dni": 0,
            "gti": 0
          },
          {
            "time_epoch": 1783972800,
            "time": "2026-07-14 04:00",
            "temp_c": 23.8,
            "temp_f": 74.8,
            "is_day": 0,
            "condition": {
              "text": "Partly Cloudy",
              "icon": "//cdn.weatherapi.com/weather/64x64/night/116.png",
              "code": 1003
            },
            "wind_mph": 3.8,
            "wind_kph": 6.1,
            "wind_degree": 137,
            "wind_dir": "SE",
            "pressure_mb": 1004.0,
            "pressure_in": 29.65,
            "precip_mm": 0.0,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 94,
            "cloud": 45,
            "feelslike_c": 18.6,
            "feelslike_f": 65.5,
            "windchill_c": 23.8,
            "windchill_f": 74.8,
            "heatindex_c": 26.3,
            "heatindex_f": 79.3,
            "dewpoint_c": 22.7,
            "dewpoint_f": 72.9,
            "will_it_rain": 0,
            "chance_of_rain": 20,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 7.0,
            "gust_kph": 11.2,
            "uv": 0,
            "short_rad": 0,
            "diff_rad": 0,
            "dni": 0,
            "gti": 0
          },
          {
            "time_epoch": 1783976400,
            "time": "2026-07-14 05:00",
            "temp_c": 23.7,
            "temp_f": 74.7,
            "is_day": 0,
            "condition": {
              "text": "Mist",
              "icon": "//cdn.weatherapi.com/weather/64x64/night/143.png",
              "code": 1030
            },
            "wind_mph": 3.1,
            "wind_kph": 5.0,
            "wind_degree": 115,
            "wind_dir": "ESE",
            "pressure_mb": 1004.0,
            "pressure_in": 29.66,
            "precip_mm": 0.01,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 95,
            "cloud": 63,
            "feelslike_c": 18.7,
            "feelslike_f": 65.7,
            "windchill_c": 23.7,
            "windchill_f": 74.7,
            "heatindex_c": 26.2,
            "heatindex_f": 79.1,
            "dewpoint_c": 22.8,
            "dewpoint_f": 73.0,
            "will_it_rain": 0,
            "chance_of_rain": 29,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 2.0,
            "vis_miles": 1.0,
            "gust_mph": 5.6,
            "gust_kph": 9.0,
            "uv": 0,
            "short_rad": 0,
            "diff_rad": 0,
            "dni": 0,
            "gti": 0
          },
          {
            "time_epoch": 1783980000,
            "time": "2026-07-14 06:00",
            "temp_c": 23.8,
            "temp_f": 74.8,
            "is_day": 1,
            "condition": {
              "text": "Mist",
              "icon": "//cdn.weatherapi.com/weather/64x64/day/143.png",
              "code": 1030
            },
            "wind_mph": 2.5,
            "wind_kph": 4.0,
            "wind_degree": 115,
            "wind_dir": "ESE",
            "pressure_mb": 1004.0,
            "pressure_in": 29.66,
            "precip_mm": 0.0,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 95,
            "cloud": 52,
            "feelslike_c": 19.0,
            "feelslike_f": 66.2,
            "windchill_c": 23.8,
            "windchill_f": 74.8,
            "heatindex_c": 26.3,
            "heatindex_f": 79.3,
            "dewpoint_c": 22.9,
            "dewpoint_f": 73.2,
            "will_it_rain": 0,
            "chance_of_rain": 26,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 2.0,
            "vis_miles": 1.0,
            "gust_mph": 4.3,
            "gust_kph": 6.9,
            "uv": 0.0,
            "short_rad": 0.64,
            "diff_rad": 0.3,
            "dni": 0.0,
            "gti": 0.62
          },
          {
            "time_epoch": 1783983600,
            "time": "2026-07-14 07:00",
            "temp_c": 25.1,
            "temp_f": 77.2,
            "is_day": 1,
            "condition": {
              "text": "Patchy rain nearby",
              "icon": "//cdn.weatherapi.com/weather/64x64/day/176.png",
              "code": 1063
            },
            "wind_mph": 2.0,
            "wind_kph": 3.2,
            "wind_degree": 98,
            "wind_dir": "E",
            "pressure_mb": 1005.0,
            "pressure_in": 29.67,
            "precip_mm": 0.01,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 91,
            "cloud": 62,
            "feelslike_c": 20.8,
            "feelslike_f": 69.4,
            "windchill_c": 25.1,
            "windchill_f": 77.2,
            "heatindex_c": 28.0,
            "heatindex_f": 82.4,
            "dewpoint_c": 23.5,
            "dewpoint_f": 74.4,
            "will_it_rain": 0,
            "chance_of_rain": 23,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 2.9,
            "gust_kph": 4.6,
            "uv": 0.6,
            "short_rad": 14.21,
            "diff_rad": 7.63,
            "dni": 0.22,
            "gti": 13.7
          },
          {
            "time_epoch": 1783987200,
            "time": "2026-07-14 08:00",
            "temp_c": 26.5,
            "temp_f": 79.7,
            "is_day": 1,
            "condition": {
              "text": "Patchy rain nearby",
              "icon": "//cdn.weatherapi.com/weather/64x64/day/176.png",
              "code": 1063
            },
            "wind_mph": 3.4,
            "wind_kph": 5.4,
            "wind_degree": 112,
            "wind_dir": "ESE",
            "pressure_mb": 1005.0,
            "pressure_in": 29.68,
            "precip_mm": 0.05,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 84,
            "cloud": 67,
            "feelslike_c": 27.2,
            "feelslike_f": 81.0,
            "windchill_c": 26.5,
            "windchill_f": 79.7,
            "heatindex_c": 29.8,
            "heatindex_f": 85.7,
            "dewpoint_c": 23.5,
            "dewpoint_f": 74.4,
            "will_it_rain": 0,
            "chance_of_rain": 22,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 4.1,
            "gust_kph": 6.6,
            "uv": 1.9,
            "short_rad": 50.83,
            "diff_rad": 26.81,
            "dni": 2.76,
            "gti": 49.25
          },
          {
            "time_epoch": 1783990800,
            "time": "2026-07-14 09:00",
            "temp_c": 28.0,
            "temp_f": 82.4,
            "is_day": 1,
            "condition": {
              "text": "Patchy rain nearby",
              "icon": "//cdn.weatherapi.com/weather/64x64/day/176.png",
              "code": 1063
            },
            "wind_mph": 5.8,
            "wind_kph": 9.4,
            "wind_degree": 114,
            "wind_dir": "ESE",
            "pressure_mb": 1005.0,
            "pressure_in": 29.68,
            "precip_mm": 0.07,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 76,
            "cloud": 70,
            "feelslike_c": 31.5,
            "feelslike_f": 88.7,
            "windchill_c": 28.0,
            "windchill_f": 82.4,
            "heatindex_c": 31.7,
            "heatindex_f": 89.1,
            "dewpoint_c": 23.4,
            "dewpoint_f": 74.0,
            "will_it_rain": 0,
            "chance_of_rain": 21,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 6.7,
            "gust_kph": 10.8,
            "uv": 4.4,
            "short_rad": 447.58,
            "diff_rad": 187.77,
            "dni": 0.0,
            "gti": 0.0
          },
          {
            "time_epoch": 1783994400,
            "time": "2026-07-14 10:00",
            "temp_c": 29.4,
            "temp_f": 85.0,
            "is_day": 1,
            "condition": {
              "text": "Light rain shower",
              "icon": "//cdn.weatherapi.com/weather/64x64/day/353.png",
              "code": 1240
            },
            "wind_mph": 7.8,
            "wind_kph": 12.6,
            "wind_degree": 123,
            "wind_dir": "SE",
            "pressure_mb": 1005.0,
            "pressure_in": 29.67,
            "precip_mm": 0.51,
            "precip_in": 0.02,
            "snow_cm": 0.0,
            "humidity": 70,
            "cloud": 83,
            "feelslike_c": 33.6,
            "feelslike_f": 92.5,
            "windchill_c": 29.4,
            "windchill_f": 85.0,
            "heatindex_c": 33.7,
            "heatindex_f": 92.6,
            "dewpoint_c": 23.4,
            "dewpoint_f": 74.0,
            "will_it_rain": 0,
            "chance_of_rain": 42,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 9.3,
            "gust_kph": 14.9,
            "uv": 7.6,
            "short_rad": 564.58,
            "diff_rad": 167.43,
            "dni": 0.0,
            "gti": 0.0
          },
          {
            "time_epoch": 1783998000,
            "time": "2026-07-14 11:00",
            "temp_c": 30.0,
            "temp_f": 86.0,
            "is_day": 1,
            "condition": {
              "text": "Light rain shower",
              "icon": "//cdn.weatherapi.com/weather/64x64/day/353.png",
              "code": 1240
            },
            "wind_mph": 9.4,
            "wind_kph": 15.1,
            "wind_degree": 134,
            "wind_dir": "SE",
            "pressure_mb": 1005.0,
            "pressure_in": 29.67,
            "precip_mm": 0.43,
            "precip_in": 0.02,
            "snow_cm": 0.0,
            "humidity": 68,
            "cloud": 89,
            "feelslike_c": 34.6,
            "feelslike_f": 94.3,
            "windchill_c": 30.0,
            "windchill_f": 86.0,
            "heatindex_c": 34.6,
            "heatindex_f": 94.3,
            "dewpoint_c": 23.5,
            "dewpoint_f": 74.2,
            "will_it_rain": 0,
            "chance_of_rain": 39,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 12.2,
            "gust_kph": 19.6,
            "uv": 9.1,
            "short_rad": 626.64,
            "diff_rad": 196.54,
            "dni": 0.0,
            "gti": 0.0
          },
          {
            "time_epoch": 1784001600,
            "time": "2026-07-14 12:00",
            "temp_c": 31.5,
            "temp_f": 88.7,
            "is_day": 1,
            "condition": {
              "text": "Patchy rain nearby",
              "icon": "//cdn.weatherapi.com/weather/64x64/day/176.png",
              "code": 1063
            },
            "wind_mph": 9.8,
            "wind_kph": 15.8,
            "wind_degree": 135,
            "wind_dir": "SE",
            "pressure_mb": 1004.0,
            "pressure_in": 29.65,
            "precip_mm": 0.02,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 60,
            "cloud": 57,
            "feelslike_c": 36.0,
            "feelslike_f": 96.8,
            "windchill_c": 31.5,
            "windchill_f": 88.7,
            "heatindex_c": 36.2,
            "heatindex_f": 97.2,
            "dewpoint_c": 22.9,
            "dewpoint_f": 73.2,
            "will_it_rain": 0,
            "chance_of_rain": 9,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 13.0,
            "gust_kph": 20.8,
            "uv": 10.7,
            "short_rad": 676.64,
            "diff_rad": 211.86,
            "dni": 0.0,
            "gti": 0.0
          },
          {
            "time_epoch": 1784005200,
            "time": "2026-07-14 13:00",
            "temp_c": 32.2,
            "temp_f": 90.0,
            "is_day": 1,
            "condition": {
              "text": "Light rain shower",
              "icon": "//cdn.weatherapi.com/weather/64x64/day/353.png",
              "code": 1240
            },
            "wind_mph": 11.9,
            "wind_kph": 19.1,
            "wind_degree": 123,
            "wind_dir": "SE",
            "pressure_mb": 1003.0,
            "pressure_in": 29.62,
            "precip_mm": 0.23,
            "precip_in": 0.01,
            "snow_cm": 0.0,
            "humidity": 57,
            "cloud": 100,
            "feelslike_c": 36.7,
            "feelslike_f": 98.1,
            "windchill_c": 32.2,
            "windchill_f": 90.0,
            "heatindex_c": 37.0,
            "heatindex_f": 98.6,
            "dewpoint_c": 22.7,
            "dewpoint_f": 72.8,
            "will_it_rain": 0,
            "chance_of_rain": 26,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 15.6,
            "gust_kph": 25.1,
            "uv": 10.8,
            "short_rad": 726.66,
            "diff_rad": 215.49,
            "dni": 0.0,
            "gti": 0.0
          },
          {
            "time_epoch": 1784008800,
            "time": "2026-07-14 14:00",
            "temp_c": 30.7,
            "temp_f": 87.2,
            "is_day": 1,
            "condition": {
              "text": "Patchy rain nearby",
              "icon": "//cdn.weatherapi.com/weather/64x64/day/176.png",
              "code": 1063
            },
            "wind_mph": 13.4,
            "wind_kph": 21.6,
            "wind_degree": 130,
            "wind_dir": "SE",
            "pressure_mb": 1003.0,
            "pressure_in": 29.62,
            "precip_mm": 0.23,
            "precip_in": 0.01,
            "snow_cm": 0.0,
            "humidity": 66,
            "cloud": 76,
            "feelslike_c": 35.6,
            "feelslike_f": 96.1,
            "windchill_c": 30.7,
            "windchill_f": 87.2,
            "heatindex_c": 35.6,
            "heatindex_f": 96.1,
            "dewpoint_c": 23.5,
            "dewpoint_f": 74.3,
            "will_it_rain": 0,
            "chance_of_rain": 25,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 9.0,
            "vis_miles": 5.0,
            "gust_mph": 18.6,
            "gust_kph": 30.0,
            "uv": 8.1,
            "short_rad": 715.63,
            "diff_rad": 229.61,
            "dni": 0.0,
            "gti": 0.0
          },
          {
            "time_epoch": 1784012400,
            "time": "2026-07-14 15:00",
            "temp_c": 31.1,
            "temp_f": 87.9,
            "is_day": 1,
            "condition": {
              "text": "Patchy rain nearby",
              "icon": "//cdn.weatherapi.com/weather/64x64/day/176.png",
              "code": 1063
            },
            "wind_mph": 12.8,
            "wind_kph": 20.5,
            "wind_degree": 129,
            "wind_dir": "SE",
            "pressure_mb": 1002.0,
            "pressure_in": 29.6,
            "precip_mm": 0.07,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 63,
            "cloud": 61,
            "feelslike_c": 35.7,
            "feelslike_f": 96.3,
            "windchill_c": 31.1,
            "windchill_f": 87.9,
            "heatindex_c": 35.8,
            "heatindex_f": 96.5,
            "dewpoint_c": 23.2,
            "dewpoint_f": 73.7,
            "will_it_rain": 0,
            "chance_of_rain": 17,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 14.7,
            "gust_kph": 23.6,
            "uv": 6.2,
            "short_rad": 812.52,
            "diff_rad": 175.95,
            "dni": 0.0,
            "gti": 0.0
          },
          {
            "time_epoch": 1784016000,
            "time": "2026-07-14 16:00",
            "temp_c": 30.1,
            "temp_f": 86.2,
            "is_day": 1,
            "condition": {
              "text": "Patchy rain nearby",
              "icon": "//cdn.weatherapi.com/weather/64x64/day/176.png",
              "code": 1063
            },
            "wind_mph": 12.5,
            "wind_kph": 20.2,
            "wind_degree": 131,
            "wind_dir": "SE",
            "pressure_mb": 1003.0,
            "pressure_in": 29.61,
            "precip_mm": 0.37,
            "precip_in": 0.01,
            "snow_cm": 0.0,
            "humidity": 68,
            "cloud": 79,
            "feelslike_c": 34.9,
            "feelslike_f": 94.8,
            "windchill_c": 30.1,
            "windchill_f": 86.3,
            "heatindex_c": 34.9,
            "heatindex_f": 94.8,
            "dewpoint_c": 23.6,
            "dewpoint_f": 74.4,
            "will_it_rain": 0,
            "chance_of_rain": 36,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 9.0,
            "vis_miles": 5.0,
            "gust_mph": 15.1,
            "gust_kph": 24.2,
            "uv": 3.8,
            "short_rad": 712.68,
            "diff_rad": 183.41,
            "dni": 0.0,
            "gti": 0.0
          },
          {
            "time_epoch": 1784019600,
            "time": "2026-07-14 17:00",
            "temp_c": 28.8,
            "temp_f": 83.8,
            "is_day": 1,
            "condition": {
              "text": "Patchy light rain in area with thunder",
              "icon": "//cdn.weatherapi.com/weather/64x64/day/386.png",
              "code": 1273
            },
            "wind_mph": 10.3,
            "wind_kph": 16.6,
            "wind_degree": 129,
            "wind_dir": "SE",
            "pressure_mb": 1002.0,
            "pressure_in": 29.6,
            "precip_mm": 0.43,
            "precip_in": 0.02,
            "snow_cm": 0.0,
            "humidity": 76,
            "cloud": 79,
            "feelslike_c": 33.3,
            "feelslike_f": 91.9,
            "windchill_c": 28.8,
            "windchill_f": 83.8,
            "heatindex_c": 33.4,
            "heatindex_f": 92.1,
            "dewpoint_c": 24.1,
            "dewpoint_f": 75.4,
            "will_it_rain": 0,
            "chance_of_rain": 41,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 13.0,
            "gust_kph": 21.0,
            "uv": 1.7,
            "short_rad": 641.42,
            "diff_rad": 146.77,
            "dni": 0.0,
            "gti": 0.0
          },
          {
            "time_epoch": 1784023200,
            "time": "2026-07-14 18:00",
            "temp_c": 26.9,
            "temp_f": 80.3,
            "is_day": 1,
            "condition": {
              "text": "Light rain shower",
              "icon": "//cdn.weatherapi.com/weather/64x64/day/353.png",
              "code": 1240
            },
            "wind_mph": 11.6,
            "wind_kph": 18.7,
            "wind_degree": 128,
            "wind_dir": "SE",
            "pressure_mb": 1003.0,
            "pressure_in": 29.63,
            "precip_mm": 0.73,
            "precip_in": 0.03,
            "snow_cm": 0.0,
            "humidity": 85,
            "cloud": 71,
            "feelslike_c": 29.1,
            "feelslike_f": 84.4,
            "windchill_c": 26.9,
            "windchill_f": 80.3,
            "heatindex_c": 30.6,
            "heatindex_f": 87.0,
            "dewpoint_c": 24.1,
            "dewpoint_f": 75.3,
            "will_it_rain": 0,
            "chance_of_rain": 55,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 17.4,
            "gust_kph": 27.9,
            "uv": 0.4,
            "short_rad": 551.06,
            "diff_rad": 128.04,
            "dni": 0.0,
            "gti": 0.0
          },
          {
            "time_epoch": 1784026800,
            "time": "2026-07-14 19:00",
            "temp_c": 25.0,
            "temp_f": 77.0,
            "is_day": 1,
            "condition": {
              "text": "Patchy rain nearby",
              "icon": "//cdn.weatherapi.com/weather/64x64/day/176.png",
              "code": 1063
            },
            "wind_mph": 9.2,
            "wind_kph": 14.8,
            "wind_degree": 137,
            "wind_dir": "SE",
            "pressure_mb": 1004.0,
            "pressure_in": 29.64,
            "precip_mm": 0.14,
            "precip_in": 0.01,
            "snow_cm": 0.0,
            "humidity": 91,
            "cloud": 71,
            "feelslike_c": 18.2,
            "feelslike_f": 64.8,
            "windchill_c": 25.0,
            "windchill_f": 77.0,
            "heatindex_c": 27.9,
            "heatindex_f": 82.2,
            "dewpoint_c": 23.5,
            "dewpoint_f": 74.3,
            "will_it_rain": 0,
            "chance_of_rain": 35,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 14.7,
            "gust_kph": 23.7,
            "uv": 0.0,
            "short_rad": 457.02,
            "diff_rad": 108.9,
            "dni": 0.0,
            "gti": 0.0
          },
          {
            "time_epoch": 1784030400,
            "time": "2026-07-14 20:00",
            "temp_c": 24.0,
            "temp_f": 75.2,
            "is_day": 0,
            "condition": {
              "text": "Patchy rain nearby",
              "icon": "//cdn.weatherapi.com/weather/64x64/night/176.png",
              "code": 1063
            },
            "wind_mph": 6.9,
            "wind_kph": 11.2,
            "wind_degree": 136,
            "wind_dir": "SE",
            "pressure_mb": 1005.0,
            "pressure_in": 29.67,
            "precip_mm": 0.02,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 94,
            "cloud": 58,
            "feelslike_c": 17.8,
            "feelslike_f": 64.0,
            "windchill_c": 24.0,
            "windchill_f": 75.2,
            "heatindex_c": 26.5,
            "heatindex_f": 79.7,
            "dewpoint_c": 22.9,
            "dewpoint_f": 73.2,
            "will_it_rain": 0,
            "chance_of_rain": 24,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 11.5,
            "gust_kph": 18.5,
            "uv": 0,
            "short_rad": 0,
            "diff_rad": 0,
            "dni": 0,
            "gti": 0
          },
          {
            "time_epoch": 1784034000,
            "time": "2026-07-14 21:00",
            "temp_c": 23.9,
            "temp_f": 75.0,
            "is_day": 0,
            "condition": {
              "text": "Patchy rain nearby",
              "icon": "//cdn.weatherapi.com/weather/64x64/night/176.png",
              "code": 1063
            },
            "wind_mph": 8.1,
            "wind_kph": 13.0,
            "wind_degree": 129,
            "wind_dir": "SE",
            "pressure_mb": 1005.0,
            "pressure_in": 29.69,
            "precip_mm": 0.04,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 94,
            "cloud": 73,
            "feelslike_c": 17.4,
            "feelslike_f": 63.3,
            "windchill_c": 23.9,
            "windchill_f": 75.1,
            "heatindex_c": 26.4,
            "heatindex_f": 79.5,
            "dewpoint_c": 22.8,
            "dewpoint_f": 73.1,
            "will_it_rain": 0,
            "chance_of_rain": 29,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 12.9,
            "gust_kph": 20.7,
            "uv": 0,
            "short_rad": 0,
            "diff_rad": 0,
            "dni": 0,
            "gti": 0
          },
          {
            "time_epoch": 1784037600,
            "time": "2026-07-14 22:00",
            "temp_c": 23.8,
            "temp_f": 74.8,
            "is_day": 0,
            "condition": {
              "text": "Patchy rain nearby",
              "icon": "//cdn.weatherapi.com/weather/64x64/night/176.png",
              "code": 1063
            },
            "wind_mph": 10.5,
            "wind_kph": 16.9,
            "wind_degree": 132,
            "wind_dir": "SE",
            "pressure_mb": 1006.0,
            "pressure_in": 29.69,
            "precip_mm": 0.01,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 93,
            "cloud": 94,
            "feelslike_c": 16.5,
            "feelslike_f": 61.7,
            "windchill_c": 23.8,
            "windchill_f": 74.8,
            "heatindex_c": 26.2,
            "heatindex_f": 79.2,
            "dewpoint_c": 22.5,
            "dewpoint_f": 72.6,
            "will_it_rain": 0,
            "chance_of_rain": 31,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 16.7,
            "gust_kph": 26.9,
            "uv": 0,
            "short_rad": 0,
            "diff_rad": 0,
            "dni": 0,
            "gti": 0
          },
          {
            "time_epoch": 1784041200,
            "time": "2026-07-14 23:00",
            "temp_c": 23.6,
            "temp_f": 74.5,
            "is_day": 0,
            "condition": {
              "text": "Patchy rain nearby",
              "icon": "//cdn.weatherapi.com/weather/64x64/night/176.png",
              "code": 1063
            },
            "wind_mph": 11.2,
            "wind_kph": 18.0,
            "wind_degree": 137,
            "wind_dir": "SE",
            "pressure_mb": 1006.0,
            "pressure_in": 29.69,
            "precip_mm": 0.02,
            "precip_in": 0.0,
            "snow_cm": 0.0,
            "humidity": 92,
            "cloud": 100,
            "feelslike_c": 16.1,
            "feelslike_f": 61.0,
            "windchill_c": 23.6,
            "windchill_f": 74.5,
            "heatindex_c": 26.0,
            "heatindex_f": 78.8,
            "dewpoint_c": 22.3,
            "dewpoint_f": 72.2,
            "will_it_rain": 0,
            "chance_of_rain": 33,
            "will_it_snow": 0,
            "chance_of_snow": 0,
            "vis_km": 10.0,
            "vis_miles": 6.0,
            "gust_mph": 17.2,
            "gust_kph": 27.7,
            "uv": 0,
            "short_rad": 0,
            "diff_rad": 0,
            "dni": 0,
            "gti": 0
          }
        ]
      }
    ]
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment