Very satisfied, because until now I could only use this module with the Arduino libraries.
Two notices about this module:
At first I used the small built-in buttons to change stations. After pressing them 30 or 40 times during testing, they literally blew themselves up.
The module does not have the GPIO1 and GPIO3 pins accessible, so they cannot be linked to recover the PA 192.168.4.1 (RECOVERY MODE) configuration. If you make a mistake in the Wifi configuration, there is no choice but to re-record the system.
I have programmed a new Internet radio which, at least for me, works fine. A first version, minimal, with only one button to change the station:
Code: [Local Link Removed for Guests]
' Lilygo TTGO T-Display ESP32 with PCM5102 I2S DAC
' Tested with Annex32 CAN 1.47.2
' PCM510 ESP32
' ------ -------
' BCK GPIO27
' DIN GPIO02
' LCK GPIO26
' GND GND
' VIN +5V
' SCK GND (to avoid oscillations)
background = tft.color(yellow)
foreground = tft.color(black)
brightness = 128 ' 0 to 255
gosub TFT_init
separator$ = "="
file$ = "/station.txt"
' numLines = number of stations minus 1: the
' subscript of an array always starts with zero
numLines = word.count(file.read$(file$), separator$) - 1
dim name$(numLines)
dim url$(numLines)
gosub loadArrays
station = 0
title$ = ""
volume = 75
gosub Play_init
onplay infoStation ' When receiving streaming metadata
init = 1
pin.mode 22, input, pullup
interrupt 22, change_Station
goto bucle
WAIT
' ---------------------------------
bucle:
while 1
j = 257
for i = 1 to 18 ' scrolls first 18 characters of title
line$ = mid$(title$, 1, i)
display line$, j, 92
j = j - 12
next i
j = 53
for i = 2 to len(title$) - 12 ' scrolls remaining title characters
line$ = mid$(title$, i, 18)
display line$, j, 92
next i
wend
return
END
' --------------------------------------
loadArrays:
for i = 1 to numLines
line$ = file.read$(file$, i)
if line$ = "_EOF_" then EXIT FOR
line$ = left$(line$, len(line$)-1) ' remove cr from end of line
separator = instr(line$, separator$)
name$(i-1) = left$(line$, separator-1)
url$(i-1) = mid$(line$, separator+1)
next i
' uncomments for debug
' wlog string$(20,"*"); " STATIONS "; string$(20,"*")
' for i = 0 to numLines-1
' wlog name$(i); " <---> "; url$(i)
' next i
' wlog
return
' --------------------------------------
TFT_init:
tft.init 2 ' Orientation Portrait Reversed
tft.brightness brightness ' 0 to 255
tft.text.color foreground, background
tft.text.align 0
return
' --------------------------------------
Play_init:
play.setup 1, 64
play.volume volume
play.stream url$(station), 20000
tft.fill background
tft.text.font 4
tft.text.draw name$(station), 50, 62
tft.text.font 3
' frame for bar level meter
tft.rect 45, 120, 227, 60, black
tft.line 46, 150, 271, 150, black
return
' --------------------------------------
InfoStation:
info$ = play.message$
' wlog info$
title = instr(info$, "StreamTitle=")
if title <> 0 then
title$ = mid$(info$, title + 12)
else
title$ = "No title information"
endif
select case name$(station) ' very special cases
case "The 40's sounds"
title$ = replace$(title$, "Big Band Swing Jazz Jive 40s 50s", "")
end select
blanks = 18 - (len(title$) MOD 18)
title$ = title$ + space$(blanks)
' wlog title$
return
' --------------------------------------
change_Station:
if pin(22) = 0 then return
if init = 1 then ' trick to avoid triggering interrupt on boot
init = 0
return
endif
pause 20 ' adjust for the best button debounce
if pin(22) = 1 then
station = station + 1
if station = numLines then station = 0
gosub Play_init
endif
return
' ============================================
SUB display(t$, x, y)
LOCAL l, r
' calculate and draw vumeter bars
l = convert.map(play.vu_L, 0, 10000, 0, 218)
r = convert.map(play.vu_R, 0, 10000, 0, 218)
tft.rect 50, 125, l, 20, red, 1
tft.rect 50, 155, r, 20, blue, 1
' Scroll song title
tft.text.col foreground
tft.text.draw line$, x, y
pause 200
' Erase vumeter bars
tft.rect 50, 125, l, 20, background, 1
tft.rect 50, 155, r, 20, background, 1
' Erase song title
tft.text.col background
tft.text.draw line$, x, y
END SUB
https://youtu.be/RXvKQKpZAR4
A second version, extended, with a rotary encoder to change the station:
Code: [Local Link Removed for Guests]
' File: "/radio2.bas"
' Lilygo TTGO T-Display ESP32 with PCM5102 I2S DAC
' Tested with Annex32 CAN 1.47.2
' PCM510 ESP32
' ------ -------
' BCK GPIO27
' DIN GPIO02
' LCK GPIO26
' GND GND
' VIN +5V
' SCK GND (to avoid oscillations)
background = tft.color(yellow)
foreground = tft.color(black)
brightness = 25 ' 0 to 255
gosub TFT_init
separator$ = "="
file$ = "/station.txt"
' numLines = number of stations minus 1: the
' subscript of an array always starts with zero
numLines = word.count(file.read$(file$), separator$) - 1
dim name$(numLines)
dim url$(numLines)
gosub loadArrays
if file.exists("/last.dat") then ' remember the last tuned station
station = val(file.read$("/last.dat"))
else
last$ = "0"
file.save "/last.dat", last$
station = 0
endif
volume = 70
title$ = ""
gosub Play_init
onplay infoStation ' When receiving streaming metadata
init = 1
pin.mode 21, input
pin.mode 22, input
' if you move the rotary encoder:
interrupt 21, loadDial
interrupt 22, loadDial
goto bucle
WAIT
' ---------------------------------
bucle:
while 1
j = 257
for i = 1 to 18 ' scrolls first 18 characters of title
line$ = mid$(title$, 1, i)
display line$, j, 92
j = j - 12
next i
j = 53
for i = 2 to len(title$) - 12 ' scrolls remaining title characters
line$ = mid$(title$, i, 18)
display line$, j, 92
next i
wend
return
END
' --------------------------------------
loadArrays:
for i = 1 to numLines
line$ = file.read$(file$, i)
if line$ = "_EOF_" then EXIT FOR
line$ = left$(line$, len(line$)-1) ' remove cr from end of line
separator = instr(line$, separator$)
name$(i-1) = left$(line$, separator-1)
url$(i-1) = mid$(line$, separator+1)
next i
' uncomments for debug:
' wlog string$(20,"*"); " STATIONS "; string$(20,"*")
' for i = 0 to numLines-1
' wlog name$(i); " <---> "; url$(i)
' next i
' wlog
return
' --------------------------------------
TFT_init:
tft.init 2 ' Orientation Portrait Reversed
tft.brightness brightness
tft.text.color foreground, background
tft.text.align 0
return
' --------------------------------------
Play_init:
play.setup 1, 64
play.volume volume
play.stream url$(station), 15000
tft.fill background
tft.text.font 4
tft.text.draw name$(station), 50, 62
tft.text.font 3
' frame for bar level meter
tft.rect 45, 120, 227, 60, black
tft.line 46, 150, 271, 150, black
return
' --------------------------------------
InfoStation:
info$ = play.message$
' uncomments for debug:
' wlog info$
title = instr(info$, "StreamTitle=")
if title <> 0 then
title$ = mid$(info$, title + 12)
else
title$ = "No title information"
endif
select case name$(station) ' very special cases
case "The 40's sounds"
title$ = replace$(title$, "Big Band Swing Jazz Jive 40s 50s", "")
end select
blanks = 18 - (len(title$) MOD 18)
title$ = title$ + space$(blanks)
' uncomments for debug:
' wlog title$
return
' --------------------------
loadDial:
if pin(21) = 0 then return
if pin(22) = 0 then return
if init = 1 then ' trick to avoid triggering interrupt on boot
init = 0
return
endif
r = bas.load "/dial.bas"
return
' --------------------------
SUB display(t$, x, y)
LOCAL l, r
' calculate and draw vumeter bars
l = convert.map(play.vu_L, 0, 10000, 0, 218)
r = convert.map(play.vu_R, 0, 10000, 0, 218)
tft.rect 50, 125, l, 20, red, 1
tft.rect 50, 155, r, 20, blue, 1
' Scroll song title
tft.text.col foreground
tft.text.draw line$, x, y
pause 200
' Erase vumeter bars
tft.rect 50, 125, l, 20, background, 1
tft.rect 50, 155, r, 20, background, 1
' Erase song title
tft.text.col background
tft.text.draw line$, x, y
END SUB
Code: [Local Link Removed for Guests]
' File "/dial.bas"
' Rotary encoder to change stations
' KY-04 ESP32
' ----- ------
' CLK -> GPIO21
' DT -> GPIO22
' SW -> N/C
' + -> 3V3
' GND -> GND
dt = 21
clk = 22
pin.mode dt, input
pin.mode clk, input
separator$ = "="
file$ = "/station.txt"
numLines = word.count(file.read$(file$), separator$) - 1
dim name$(numLines)
dim url$(numLines)
gosub loadArrays
background = tft.color(yellow)
foreground = tft.color(black)
brightness = 25 ' 0 to 255
gosub TFT_init
play.setup 1, 64
play.volume 70
station = val(file.read$("/last.dat"))
gosub menu
new = station
old = station
min = 0
max = numLines-1
inactivity = 8000 ' 15 seconds without moving and returns
t = millis
' loop waiting for rotary encoder turn:
while 1
gosub decode
if new <> old then
gosub viewValue
old = new
station = new
gosub menu
t = millis
endif
elapsed = millis - t
if elapsed > inactivity then ' return after idle time
' uncomment for debug
' wlog time$
' t = millis
' comment for debug
play.stop
file.save "/last.dat", str$(station)
r = bas.load "/radio2.bas"
endif
wend
END
' --------------------------------------
loadArrays:
for i = 1 to numLines
line$ = file.read$(file$, i)
if line$ = "_EOF_" then EXIT FOR
line$ = left$(line$, len(line$)-1)
separator = instr(line$, separator$)
name$(i-1) = left$(line$, separator-1)
url$(i-1) = mid$(line$, separator+1)
next i
return
' --------------------------------------
TFT_init:
tft.init 2 ' Orientation Portrait Reversed
tft.brightness brightness
tft.text.color foreground, background
tft.text.align 0
return
' --------------------------------------
menu:
tft.fill background
tft.text.font 4
last = 3
offset = station-1
y = 92
select case station
case 0 ' first array item
offset = 0
y = 62
case numLines-1 ' last array item
last = numLines-station
end select
for row = 0 to last
tft.text.draw name$(row+offset), 50, (row*30) + 62
next row
tft.text.color white, blue
tft.text.draw name$(station), 50, y
tft.text.color foreground, background
play.stream url$(station), 15000
return
' -------------------------------------
decode:
l = pin(clk)
r = pin(dt)
if l=0 AND r=1 then new = new + 1
if new > max then new = max
if l=1 AND r=0 then new = new - 1
if new < min then new = min
do
l = pin(clk)
r = pin(dt)
pause 10 ' modify for better debounce
loop until l=1 AND r=1
return
' ---------------------------------------
viewValue:
if new > old then wlog "Derecha "; new
if new < old then wlog "Izquierda "; new
return