PicoCalc Internet Cat Facts For WebMite MMBasic Firmware

Pushing a Pico 2W to navigate the modern web is no small feat - it’s like teaching a pocket calculator to read a newspaper while someone is constantly trying to fold it in different ways.

By tackling TCP handshakes, dynamic headers, and JSON parsing, we move beyond simple “Hello World” WiFi projects and into real-world IoT engineering. Using a cat fact API to prove the concept is the perfect ‘hacker’ practical and fun way to do it.

I’m quite new to the PicoCalc and to MMBasic, and this is the culmination of my first web-based project ‘co-piloted’ by Google AI. I’m personally finding the ‘old-school’ WebMite MMBasic firmware for the PicoCalc has a lot to offer, so I hope the Community will enjoy this ‘cut and paste’ contribution.

Note: Occasionally the script may fail to produce a cat fact. This can happen if the parsing script encounters escape characters within the JSON “fact” data itself, thus throwing the script (as-is) a curveball. No worries - just try again for another fact :slight_smile:

’ ************************************************************
’ * PICOCALC INTERNET CAT FACTS - COMMUNITY EDITION *
’ * A “Port 80 Bridge” Solution for Legacy WebMite Firmware *
’ * Developed by: Xander & his adaptive peer collaborator *
’ ************************************************************

’ — SYSTEM SETUP —
’ 256 * 8 = 2048 bytes. Essential to catch long Cloudflare headers.
Dim buff%(256)
’ Standard string for the cleaned-up fact. 255 is the MMBasic max.
Dim cleanFact$ LENGTH 255

’ NOTE: Ensure ‘OPTION LCDPANEL CONSOLE’ was set at the command prompt
’ to allow the PRINT commands to scroll and wrap on the 320x320 screen.

’ — MAIN PROGRAM LOOP —
Do
CLS
Print “"
Print "
PICOCALC CAT FACTS "
Print "

Print “”
Print “STATUS: READY”
Print “ACTION: PRESS ANY KEY…”

’ Loop until a key is pressed to trigger the fetch
Do : Loop Until Inkey$ <> “”

FetchCatFact

’ Debounce pause to prevent accidental double-triggers
Pause 1000
Loop

Sub FetchCatFact
Local r$, pStart, pEnd

’ 1. HOUSEKEEPING
’ Zero out the buffer to prevent “ghost” data from previous facts
Math SET 0, buff%()
CLS
Print “SYSTEM: CONNECTING…”

’ 2. THE PORT 80 HACK
’ Most APIs force HTTPS (Port 443). We use MeowFacts on Port 80
’ to bypass SSL Handshake “400 Bad Request” errors on Pico hardware.
WEB OPEN TCP CLIENT “meowfacts.herokuapp.com”, 80
Pause 1000 ’ Give the WiFi radio time to stabilize

’ 3. THE REQUEST HEADERS
’ We pretend to be ‘curl’ to stop the server from sending a pretty HTML webpage.
r$ = “GET /?count=1 HTTP/1.0” + Chr$(13) + Chr$(10)
r$ = r$ + “Host: meowfacts.herokuapp.com” + Chr$(13) + Chr$(10)
r$ = r$ + “User-Agent: curl/7.68.0” + Chr$(13) + Chr$(10)
r$ = r$ + “Accept: application/json” + Chr$(13) + Chr$(10)
r$ = r$ + “Connection: close” + Chr$(13) + Chr$(10) + Chr$(13) + Chr$(10)

’ 4. THE DATA CATCH
WEB TCP CLIENT REQUEST r$, buff%()
Print “SYSTEM: RECEIVING BYTES…”
’ Wait 4s for the full 1KB+ response (headers are surprisingly long!)
Pause 4000
WEB CLOSE TCP CLIENT

’ 5. THE HEADER JUMP
’ Look for the specific start of the data array.
pStart = LInStr(buff%(), “data” + Chr$(34) + “:[” + Chr$(34))

If pStart > 0 Then
’ Move pointer to the start of the actual text (after data":[")
pStart = pStart + 8

' 6. THE JSON EXTRACTION
' Find the quote mark that ends the fact inside the [" ... "] array
pEnd = LInStr(buff%(), Chr$(34) + "]", pStart)

If pEnd > pStart Then
  ' pStart + 2 jumps over the [" to the first letter of the fact
  cleanFact$ = LGetStr$(buff%(), pStart, pEnd - pStart)

  ' 7. BEAUTIFIED DISPLAY
  CLS
  Print "---- DID YOU KNOW? ----"
  Print ""
  ' Call our custom word-wrap routine to avoid mid-word line breaks
  DisplayWrapped cleanFact$
  Print ""
  Print "-----------------------"
  Print "PRESS ANY KEY FOR NEXT,"
  Print "OR 'CTRL C' TO EXIT..."

  ' Wait for user interaction before returning to main menu
  Pause 500
  Do : Loop Until Inkey$ <> ""
EndIf

Else
Print “ERROR: NO DATA FOUND IN BUFFER”
Print "REC’D: “; LLen(buff%()); " BYTES”
Pause 3000
EndIf
End Sub

’ — CUSTOM WORD WRAP SUBROUTINE —
’ Prevents the console from cutting words in half at the 320px screen edge.
Sub DisplayWrapped(txt$)
Color RGB(white), RGB(black)
Local i, word$, lineLen, char$
lineLen = 0
txt$ = txt$ + " " ’ Extra space ensures the last word is processed

For i = 1 To Len(txt$)
char$ = Mid$(txt$, i, 1)

' If we hit a space, decide if the current word fits on the line
If char$ = " " Then
  ' If the word + current line > 28 chars, force a carriage return
  If (lineLen + Len(word$)) > 28 Then
    Print ""
    lineLen = 0
  EndIf
  Print word$ + " ";
  lineLen = lineLen + Len(word$) + 1
  word$ = ""
Else
  ' Build the word character by character
  word$ = word$ + char$
EndIf

Next i
Print “”
Color RGB(green), RGB(black)
End Sub

Oops! Apologies, my script didn’t maintain its formatting when submitted :frowning: