Pi 5 Stratum-1 NTP Server from ESP32 GNSS PPS

Use the kernel PPS path. Do not write a Python or C GPIO polling loop for timing. User-space timing will add scheduling latency; the kernel PPS driver timestamps the edge much earlier and exposes it as /dev/pps0.

Wiring:

ESP32 GPIO27(PPS) ----------------->  Pi 5 GPIO18 / phy pin 12
ESP32 GND         ----------------->  Pi 5 GND    / phy pin 14

Time Source Design

PPS alone is not a complete clock. It tells the Pi exactly where the second boundary is, but not which UTC second it is.

Chrony therefore needs:

  • PPS on /dev/pps0 for the precise second edge.
  • A normal time source, such as the ESP32 GNSS NTP server, for UTC date and second numbering.

Flow:

M10S GNSS
   |
   | GNSS time + PPS
   v
ESP32
   |
   | GPIO27 PPS
   v
Raspberry Pi 5 GPIO18
   |
   | kernel PPS timestamp
   v
/dev/pps0
   |
   v
chronyd
   |
   +-- PPS: precise second boundary
   +-- ESP32 NTP: UTC second/date
   |
   v
Pi 5 serves LAN NTP as stratum 1

Enable PPS on Raspberry Pi 5

Edit the Pi boot config:

sudo nano /boot/firmware/config.txt

Add this line:

dtoverlay=pps-rp1,pin=18,pull-down,schmitt-trigger

Why this overlay:

  • pps-rp1 is the Pi 5/RP1-specific PPS overlay.
  • pin=18 selects GPIO18, physical pin 12.
  • pull-down=keeps the input from floating when PPS is disconnected.
  • schmitt-trigger can help clean up marginal/noisy edges on a wire.

Do not add assert-falling-edge for the normal GNSS PPS case. The default is rising-edge assert, which is what you usually want from a GNSS 1PPS output.

Reboot:

After reboot, check that the PPS device exists:

ls -l /dev/pps*

Install Chrony and PPS Tools:

apt update
apt install chrony pps-tools

Test the PPS input before configuring Chrony:

ppstest /dev/pps0

Expected output should increment once per second:

root@lp-arm-5:~# ppstest /dev/pps0
trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
ok, found 1 source(s), now start fetching data...
source 0 - assert 1788624719.999999432, sequence: 5376 - clear  0.000000000, sequence: 0
source 0 - assert 1788624721.000000259, sequence: 5377 - clear  0.000000000, sequence: 0
source 0 - assert 1788624721.999999836, sequence: 5378 - clear  0.000000000, sequence: 0

Configure Chrony

Assume the ESP32 GNSS NTP server is reachable at:

192.168.10.90

Edit Chrony config:

sudo nano /etc/chrony/chrony.conf

Use this minimal configuration as the core of the file. Adjust the server IP and allow network for your LAN.

# Coarse UTC source.
# This gives chronyd the actual UTC second/date.
server 192.168.10.90 iburst minpoll 3 maxpoll 3 prefer

# Precise PPS source.
# ESP32 GPIO27 -> Pi 5 GPIO18 -> kernel PPS -> /dev/pps0.
refclock PPS /dev/pps0 refid PPS poll 0 prefer

# Clock discipline.
makestep 0.1 3
rtcsync

# Allow LAN clients to query this Pi as an NTP server.
# Change this to match your network.
allow 192.168.0.0/16

# Optional logging.
log tracking measurements statistics
logdir /var/log/chrony

Restart Chrony:

sudo systemctl restart chrony

Verify SynchronizationP

chronyc sources -v

Healthy output eventually looks like this:

root@lp-arm-5:~# chronyc sources -v
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
#* PPS                           0   0   377     1   -133ns[ -155ns] +/-   18ns
^- 192.168.10.90                 1   3   377     7  -2363us[-2362us] +/- 5521us

Verify NTP Serving from Another Machine:

From another Linux machine on the LAN:

ntpdate -q <PI5_IP>

Example:

ntpdate -q 192.168.0.183

Why There Is No Custom Timing Code?

The fast and low-jitter path is:

ESP32 PPS
   |
   v
Pi 5 RP1 GPIO interrupt
   |
   v
Linux PPS kernel timestamp
   |
   v
/dev/pps0
   |
   v
chronyd

A custom C or Python program would run after the kernel schedules it, which adds avoidable latency and jitter. For a stratum-1 NTP server, use the kernel PPS driver plus Chrony.

References

adjust clock 20ms with current time

  • As for my pi5 i know the it has ~5PPM, so it drift ~20ms every hours
#include <stdio.h>
#include <time.h>

int main(void)
{
    struct timespec ts;

    if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
        return 1;

    ts.tv_nsec += 20000000L;  // +20 ms

    if (ts.tv_nsec >= 1000000000L) {
        ts.tv_sec++;
        ts.tv_nsec -= 1000000000L;
    }

    if (clock_settime(CLOCK_REALTIME, &ts) != 0)
        return 1;

    return 0;
}
gcc add20ms.c -o add20ms
./add20ms
  • Other tool adjtimex that can update the frequency of current clock
@home:~$ adjtimex --print
         mode: 0
       offset: 0
    frequency: -1058757
     maxerror: 3752
     esterror: 1145
       status: 0
time_constant: 2
    precision: 1
    tolerance: 32768000
         tick: 10000
     raw time:  1787551740s 373129us = 1787551740.373129


frequency: -1058757
1 ppm = 65536
So +5.556 ppm corresponds to:
5.556 × 65536 ≈ 364446

add +5.556 ppm to the clock's existing frequency correction
-1058757 + 364446
= -694311


sudo adjtimex --freq -694311
root@lp-arm-5:/opt/docker# ntpdate 192.168.10.196
2026-08-24 13:32:32.978000 (+0530) +166337.977652 +/- 0.003123 192.168.10.196 s1 no-leap
CLOCK: time stepped by 166337.977652
CLOCK: time changed from 2026-08-22 to 2026-08-24

#### After reboot

root@lp-arm-5:~# date
Mon Aug 24 13:40:46 IST 2026

root@lp-arm-5:~# ntpdate -q 192.168.10.90
2026-08-24 14:18:12.673999 (+0530) +2234.752511 +/- 0.004031 192.168.10.90 s1 no-leap

root@lp-arm-5:~# ntpdate 192.168.10.90
2026-08-24 14:18:15.906000 (+0530) +2234.750451 +/- 0.005585 192.168.10.90 s1 no-leap
CLOCK: time stepped by 2234.750451

Openwrt ntpd and ntpq time server

root@OpenWrt:~# ntpd -w -d -p 192.168.10.196
ntpd: sending query to 192.168.10.196
ntpd: reply from 192.168.10.196: offset:-0.002124 delay:0.010506 status:0x24 strat:1 refid:0x00535047 rootdelay:0.000000 reach:0x01
ntpd: sending query to 192.168.10.196
ntpd: reply from 192.168.10.196: offset:-0.001935 delay:0.008853 status:0x24 strat:1 refid:0x00535047 rootdelay:0.000000 reach:0x03
ntpd: sending query to 192.168.10.196
ntpd: reply from 192.168.10.196: offset:+0.003002 delay:0.008686 status:0x24 strat:1 refid:0x00535047 rootdelay:0.000000 reach:0x07


uci show system | grep ntp

cat /etc/config/system

/etc/init.d/sysntpd status
Usage: ntpd [-dnqNwl] [-I IFACE] [-S PROG] [-p PEER]...

NTP client/server

	-d[d]	Verbose
	-n	Run in foreground
	-q	Quit after clock is set
	-N	Run at high priority
	-w	Do not set time (only query peers), implies -n
	-S PROG	Run PROG after stepping time, stratum change, and every 11 min
	-p PEER	Obtain time from PEER (may be repeated)
	-l	Also run as server on port 123
	-I IFACE Bind server to IFACE, implies -l

Pi5 PTP clock – /dev/ptp0

  • Pi5 has ptp
root@lp-arm-5:~# ethtool -T eth0
Time stamping parameters for eth0:
Capabilities:
	hardware-transmit
	software-transmit
	hardware-receive
	software-receive
	software-system-clock
	hardware-raw-clock
Hardware timestamp provider index: 0
Hardware timestamp provider qualifier: Precise (IEEE 1588 quality)
Hardware Transmit Timestamp Modes:
	off
	on
	onestep-sync
Hardware Receive Filter Modes:
	none
	all

root@lp-arm-5:~# phc_ctl /dev/ptp0 get
phc_ctl[644486.511]: clock time is 1787465854.590438111 or Sun Aug 23 11:47:34 2026

root@lp-arm-5:~# phc_ctl /dev/ptp0 caps
phc_ctl[644504.310]: 
capabilities:
  64000000 maximum frequency adjustment (ppb)
  0 programable alarms
  0 external time stamp channels
  0 programmable periodic signals
  0 configurable input/output pins
  has pulse per second support
  doesn't have cross timestamping support
  doesn't have adjust phase support


root@lp-arm-5:~# date
sudo phc_ctl /dev/ptp0 get
sudo hwclock -r
Sun Aug 23 13:21:04 IST 2026
phc_ctl[645456.567]: clock time is 1787466824.601451911 or Sun Aug 23 12:03:44 2026

2026-08-23 13:21:04.580550+05:30

  • Update clock on pi5
root@lp-arm-5:~# ntpdate -q 192.168.10.196
2026-08-24 11:06:42.867000 (+0530) +0.802164 +/- 0.004007 192.168.10.196 s1 no-leap
root@lp-arm-5:~# ntpdate 192.168.10.196
2026-08-24 11:06:45.468000 (+0530) +0.802924 +/- 0.003670 192.168.10.196 s1 no-leap
CLOCK: time stepped by 0.802924

Rpi4/5 NTP server and PPM Time drift test

  • So pi has 1PPM error rate on it’s clock. it should dirft ~1second per day
systemctl status systemd-timesyncd

root@lp-arm-5:~# timedatectl timesync-status
       Server: 192.168.10.196 (192.168.10.196)
Poll interval: 34min 8s (min: 32s; max 34min 8s)
         Leap: normal
      Version: 4
      Stratum: 1
    Reference: GPS
    Precision: 1us (-20)
Root distance: 0 (max: 5s)
       Offset: -79.759ms
        Delay: 177.920ms
       Jitter: 392.723ms
 Packet count: 437

root@lp-arm-5:~# timedatectl show-timesync
SystemNTPServers=192.168.10.196
FallbackNTPServers=0.debian.pool.ntp.org 1.debian.pool.ntp.org
ServerName=192.168.10.196
ServerAddress=192.168.10.196
RootDistanceMaxUSec=5s
PollIntervalMinUSec=32s
PollIntervalMaxUSec=34min 8s
PollIntervalUSec=34min 8s
NTPMessage={ Leap=0, Version=4, Mode=4, Stratum=1, Precision=-20, RootDelay=0, RootDispersion=0, Reference=GPS, OriginateTimestamp=Sat 2026-08-22 13:55:50 IST, ReceiveTimestamp=Sat 2026-08-22 13:55:50 IST, TransmitTimestamp=Sat 2026-08-22 13:55:50 IST, DestinationTimestamp=Sat 2026-08-22 13:55:50 IST, Ignored=yes, PacketCount=437, Jitter=392.723ms }
Frequency=278345

  • Sync every 30 second
PollIntervalMaxSec=30
PollIntervalMinSec=30
root@lp-arm-5:~# cat  /etc/systemd/timesyncd.conf
[Time]
NTP=192.168.10.196
#sync every 30 second
PollIntervalMaxSec=30
PollIntervalMinSec=30
FallbackNTP=0.debian.pool.ntp.org 1.debian.pool.ntp.org
[Time]
#NTP=
#FallbackNTP=0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org 3.debian.pool.ntp.org
#RootDistanceMaxSec=5
#PollIntervalMinSec=32
#PollIntervalMaxSec=2048
#ConnectionRetrySec=30
#SaveIntervalSec=60

  • stoped ntp service
root@lp-arm-5:~# timedatectl  && ntpdate -q 192.168.10.90
               Local time: Sat 2026-08-22 14:55:11 IST
           Universal time: Sat 2026-08-22 09:25:11 UTC
                 RTC time: Sat 2026-08-22 09:25:11
                Time zone: Asia/Kolkata (IST, +0530)
System clock synchronized: yes
              NTP service: inactive
          RTC in local TZ: no
2026-08-22 14:55:11.120999 (+0530) +0.017578 +/- 0.004635 192.168.10.90 s1 no-leap



root@lp-arm-5:~# while true; do     ntpdate -q 192.168.10.90;     sleep 1; done
2026-08-22 14:56:07.223000 (+0530) +0.014346 +/- 0.009613 192.168.10.90 s1 no-leap
2026-08-22 14:56:08.310000 (+0530) +0.016642 +/- 0.008483 192.168.10.90 s1 no-leap
2026-08-22 14:56:09.393000 (+0530) +0.019201 +/- 0.004101 192.168.10.90 s1 no-leap
2026-08-22 14:56:10.473000 (+0530) +0.016223 +/- 0.012315 192.168.10.90 s1 no-leap
  • After ~12 hours
root@lp-arm-5:~# head /var/log/gnss.log 
===== GNSS NTP measurement Sat Aug 22 23:12:48 IST 2026 =====
2026-08-22 23:11:43.945 offset=158783.000 us drift=N/A us/s drift=N/A ppm
2026-08-22 23:11:45.030 offset=156998.000 us drift=1625.399 us/s drift=1625.399 ppm
2026-08-22 23:11:46.114 offset=160638.000 us drift=-3348.105 us/s drift=-3348.105 ppm
2026-08-22 23:11:47.198 offset=162109.000 us drift=-1357.056 us/s drift=-1357.056 ppm

root@lp-arm-5:~# tail /var/log/gnss.log 
2026-08-23 12:07:41.968 offset=395067.000 us drift=-5542.332 us/s drift=-5542.332 ppm
2026-08-23 12:07:43.079 offset=397609.000 us drift=-2343.630 us/s drift=-2343.630 ppm
2026-08-23 12:07:44.187 offset=394536.000 us drift=2763.032 us/s drift=2763.032 ppm
First sample:
2026-08-22 23:11:43.945
offset = 158783 us
       = 158.783 ms

Last sample:
2026-08-23 12:07:50.758
offset = 389441 us
       = 389.441 ms

Therefore:
389.441 ms - 158.783 ms
= 230.658 ms

So if this trend continued, you'd expect roughly:
1 day    ≈ +428 ms
7 days   ≈ +3.0 seconds
30 days  ≈ +12.8 seconds
1 year   ≈ +156 seconds (~2.6 minutes)
  • So the Pi4 clock offset increased by approximately:
    +230.7 ms

Chrony Service useful parameter

systemctl status chrony

nano /etc/chrony/chrony.conf

server 192.168.10.196 iburst minpoll 5 maxpoll 5

#5 is (2 raise to 5) = 32sec
makestep 1 3

Startup:
update #1 → offset 2.5 s  → STEP immediately
update #2 → offset 0.2 s  → normal slew
update #3 → offset 1.2 s  → STEP immediately

Later:
update #4 → offset 2.0 s  → NO step; chrony slews it
maxupdateskew 100.0 

means if chrony estimates the clock's frequency correction with uncertainty greater than 100 ppm, it will not use that update to adjust the clock. Lower = stricter confidence requirement.
  • Latency ~3ms from wifi
@home:~$ chronyc sources -v

MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
^* gps1.home                     1   5   356    91  -2499us[-2864us] +/- 3502us

^* gps1.home                     1   5   317    31   -375us[-8253us] +/- 3580us

^* gps1.home                     1   5   237    11  -1792us[-2216us] +/- 3297us

^* gps1.home                     1   5    77    17   -564us[ -652us] +/- 5086us

raspberry pi useful commands

  • See voltage of all pin – can be used in TRNG
root@lp-arm-5:~# vcgencmd pmic_read_adc
 3V7_WL_SW_A current(0)=0.09271335A
   3V3_SYS_A current(1)=0.07026696A
   1V8_SYS_A current(2)=0.12589500A
  DDR_VDD2_A current(3)=0.00292779A
  DDR_VDDQ_A current(4)=0.00000000A
   1V1_SYS_A current(5)=0.20299340A
    0V8_SW_A current(6)=0.35523850A
  VDD_CORE_A current(7)=0.68761000A
   3V3_DAC_A current(17)=0.00000000A
   3V3_ADC_A current(18)=0.00006105A
   0V8_AON_A current(16)=0.00323565A
      HDMI_A current(22)=0.01172160A
 3V7_WL_SW_V volt(8)=3.69977600V
   3V3_SYS_V volt(9)=3.30632200V
   1V8_SYS_V volt(10)=1.79975400V
  DDR_VDD2_V volt(11)=1.10732500V
  DDR_VDDQ_V volt(12)=0.60402870V
   1V1_SYS_V volt(13)=1.10256300V
    0V8_SW_V volt(14)=0.79926660V
  VDD_CORE_V volt(15)=0.72097620V
   3V3_DAC_V volt(20)=3.30768900V
   3V3_ADC_V volt(21)=3.30585700V
   0V8_AON_V volt(19)=0.79736190V
      HDMI_V volt(23)=5.02902000V
     EXT5V_V volt(24)=5.02098000V
      BATT_V volt(25)=0.00000000V

raspberry pi boot long time – no boot / reboot issue fixed

I have raspberry pi 4 with raspbian os lite installed and the OS is directly installed on SSD which is connected with USB3.0 with connector USB-to-SATA. Whenever the power outage happens the pi some time boots and sometime it doesn’t and it also takes lots of time to boot 10min+

  • First I checked with below command what services are taking longer time and disabled docker and kubelet rpi-eeprom-update
root@lp-arm-3:~# systemd-analyze blame
1min 36.522s docker.service
     51.427s containerd.service
     50.609s rpi-eeprom-update.service
     50.590s user@1000.service
     50.221s ModemManager.service
     49.702s NetworkManager-wait-online.service
     38.108s apt-daily-upgrade.service
     32.277s dpkg-db-backup.service
      2.558s dev-sda2.device
      1.281s raspi-config.service
       670ms man-db.service
       613ms NetworkManager.service
       583ms keyboard-setup.service
       536ms systemd-logind.service
       512ms systemd-udev-trigger.service
       429ms systemd-journald.service


root@lp-arm-3:~# systemd-analyze
Startup finished in 36.419s (kernel) + 2min 33.375s (userspace) = 3min 9.794s 
multi-user.target reached after 2min 33.318s in userspace.



root@lp-arm-3:~# systemd-analyze critical-chain
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.

multi-user.target @2min 33.318s
└─kubelet.service @1min 6.646s
  └─network-online.target @55.038s
    └─NetworkManager-wait-online.service @5.315s +49.702s
      └─NetworkManager.service @4.687s +613ms
        └─dbus.service @4.552s +97ms
          └─basic.target @4.509s
            └─sockets.target @4.509s
              └─docker.socket @4.485s +23ms
                └─sysinit.target @4.468s
                  └─systemd-timesyncd.service @4.091s +375ms
                    └─systemd-tmpfiles-setup.service @3.805s +208ms
                      └─local-fs.target @3.777s
                        └─run-user-1000.mount @5.576s
                          └─local-fs-pre.target @1.650s
                            └─keyboard-setup.service @1.065s +583ms
                              └─systemd-journald.socket @1.019s
                                └─-.mount @946ms
                                  └─-.slice @946ms
  • This did not fix issue.
  • Main issue was USB SATA driver speed.
  • I enabled permanent logs for boot
journalctl --list-boots
journalctl -b -1

show only error

journalctl -b -1 -p err
Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#9 uas_eh_abort_handler 0 uas-tag 15 inflight: CMD OUT Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#9 CDB: opcode=0x2a 2a 00 01 50 21 78 00 00 08 00 Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#4 uas_eh_abort_handler 0 uas-tag 6 inflight: CMD Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#4 CDB: opcode=0x35 35 00 00 00 00 00 00 00 00 00 Feb 07 20:40:53 lp-arm-3.home kernel: scsi host0: uas_eh_device_reset_handler start Feb 07 20:40:53 lp-arm-3.home kernel: usb 2-2: reset SuperSpeed USB device number 2 using xhci_hcd Feb 07 20:40:53 lp-arm-3.home kernel: scsi host0: uas_eh_device_reset_handler success Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#8 UNKNOWN(0x2003) Result: hostbyte=0x07 driverbyte=DRIVER_OK cmd_age=61s Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#8 CDB: opcode=0x28 28 00 00 5e dc f8 00 00 10 00 Feb 07 20:40:53 lp-arm-3.home kernel: I/O error, dev sda, sector 6216952 op 0x0:(READ) flags 0x80700 phys_seg 2 prio class 2 Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#2 UNKNOWN(0x2003) Result: hostbyte=0x07 driverbyte=DRIVER_OK cmd_age=61s Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#2 CDB: opcode=0x28 28 00 02 88 f5 e0 00 00 30 00 Feb 07 20:40:53 lp-arm-3.home kernel: I/O error, dev sda, sector 42530272 op 0x0:(READ) flags 0x80700 phys_seg 6 prio class 2 Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#1 UNKNOWN(0x2003) Result: hostbyte=0x07 driverbyte=DRIVER_OK cmd_age=61s Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#1 CDB: opcode=0x28 28 00 00 5e cb c8 00 01 00 00 Feb 07 20:40:53 lp-arm-3.home kernel: I/O error, dev sda, sector 6212552 op 0x0:(READ) flags 0x80700 phys_seg 32 prio class 2 Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#3 UNKNOWN(0x2003) Result: hostbyte=0x07 driverbyte=DRIVER_OK cmd_age=61s Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#3 CDB: opcode=0x28 28 00 02 84 ee 68 00 00 50 00 Feb 07 20:40:53 lp-arm-3.home kernel: I/O error, dev sda, sector 42266216 op 0x0:(READ) flags 0x80700 phys_seg 10 prio class 2 Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#6 UNKNOWN(0x2003) Result: hostbyte=0x07 driverbyte=DRIVER_OK cmd_age=55s Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#6 CDB: opcode=0x28 28 00 02 80 6e 38 00 00 90 00 Feb 07 20:40:53 lp-arm-3.home kernel: I/O error, dev sda, sector 41971256 op 0x0:(READ) flags 0x80700 phys_seg 18 prio class 2 Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#7 UNKNOWN(0x2003) Result: hostbyte=0x07 driverbyte=DRIVER_OK cmd_age=49s Feb 07 20:40:53 lp-arm-3.home kernel: sd 0:0:0:0: [sda] tag#7 CDB: opcode=0x28 28 00 02 80 3c d0 00 00 58 00 Feb 07 20:40:53 lp-arm-3.home kernel: I/O error, dev sda, sector 41958608 op 0x0:(READ) flags 0x80700 phys_seg 11 prio class 2
  • The kernel is resetting the USB
  • Disabled UAS for SSD – fixed the issue
lsusb

#get the USB ID eg 7825:a2a4

vi /boot/firmware/cmdline.txt

append this line at the end

usb-storage.quirks=7825:a2a4:u

reboot

root@lp-arm-3:~# lsusb -t
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M
    |__ Port 2: Dev 2, If 0, Class=Mass Storage, Driver=usb-storage, 5000M
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M

usb-storage (BOT):

sends one command at a time
waits for completion
has simpler recovery
tolerates retries and delays

Get indoor temperature from your LG AC WIFI

  • Install the pythinqconnect package
 pip3 install git+https://github.com/thinq-connect/pythinqconnect.git --break-system-packages
  • Get PAT token generated
https://connect-pat.lgthinq.com/tokens
  • Get Device id
import asyncio
from aiohttp import ClientSession
# Assuming a library structure like pythinqconnect
from thinqconnect.thinq_api import ThinQApi 

############## Get device ID ###############
async def test_devices_list():
    # Setup your credentials and personal access token (PAT)
    async with ClientSession() as session:
        thinq_api = ThinQApi(
            session=session, 
            access_token='PAT',
            country_code='',  # Example: US, KR, NL
            client_id='your_client_id'
        )
        # Fetch device list
        response = await thinq_api.async_get_device_list()
        print("device_list : %s", response)

# Run the async function
asyncio.run(test_devices_list())
  • Get temp
async def get_indoor_temperature_c():
    async with ClientSession() as session:
        api = ThinQApi(
            session=session,
            access_token="PAT",
            country_code="",
            client_id="YOUR_CLIENT_ID"
        )

        status = await api.async_get_device_status(DEVICE_ID)

        temp_c = status["temperature"]["currentTemperature"]

        print(temp_c)
        return temp_c

asyncio.run(get_indoor_temperature_c())
@home:~/Downloads/c$ python3 lg.py 
29.5

https://smartsolution.developer.lge.com/en/apiManage/device_profile?s=1734593490507#tag/overview

https://github.com/thinq-connect/pythinqconnect/tree/main