blog

Categories     Timeline     RSS

Bridging to a SIM800L with a Raspberry Pico

Send GSM-AT commands from a computer via serial console > Raspberry Pi Pico > SIM800L in order to phone home.

Pins

SIM800L Raspberry Pi Pico
RX UART1_TX / GP8 / Pin 11
TX UART1_RX / GP9 / Pin 12
GND GND / Pin 38
VCC VBUS

Caution: Voltage is a little above spec this way, but it suffices for tests.

Bridge

#define S2_TX 8
#define S2_RX 9

UART Serial2(S2_TX,S2_RX,0,0);

void setup() {
  Serial.begin(9600);
  Serial2.begin(9600);
}

void loop() {
  while (Serial2.available() > 0) {
    Serial.print(Serial2.readString());
    delay(10);
  }
  while (Serial.available() > 0) {
    Serial2.print(Serial.readString());
    delay(10);
  }
}

Then open a serial console (e.g. inside the Arduino IDE)

Typical interaction

Command Meaning
ATI Get info about the SIM800L board, make sure it’s connected
AT+CSQ Check signal quality, answer: +CSQ: FLOATVAL, everything above 10,0 is OK
AT+COPS? Check net login (e.g. D1)
ATD+49123456789; Call +49 1234 56789 (mind the semicolon)
ATH Hang up

Betriebsamkeit

Ganz schön was los

Minimal three tier Golang app v2

Building on Minimal three tier Golang app, I made a three tier app with a Go frontend (as Web Assembly), a Go backend and a .txt as exemplary “data store”. Still no external dependencies, all compiling to a single binary. You need Go, Make and a browser. Compile and start with make, then open http://localhost:8000 and hit the button.

$ cat Makefile
all: hellofront hello

hellofront: hellofront.go
        GOOS=js GOARCH=wasm go build hellofront.go structures.go

hello:
        go run hello.go structures.go


$ cat structures.go
package main

type Answer struct {
        Current int
}


$ cat hellofront.go
package main

import (
        "encoding/json"
        "fmt"
        "net/http"
        "syscall/js"
)

var current js.Value

func main() {
        done := make(chan struct{}, 0)
        current = js.Global().Get("document").Call("getElementById", "current")
        js.Global().Set("GetCurrent", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
                go GetCurrent()
                return nil
        }))
        <-done
}

func GetCurrent() {
        resp, err := http.Get("/current")
        if err != nil {
                fmt.Println(err)
        }
        var res Answer
        err = json.NewDecoder(resp.Body).Decode(&res)
        if err != nil {
                fmt.Println(err)
        }
        current.Set("innerText", res.Current)
}


$ cat hello.go
package main

import (
	_ "embed"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

//go:embed hellofront
var wasm []byte

// copied from $(go env GOROOT)/misc/wasm/wasm_exec.js
//go:embed wasm_exec.js
var wasm_exec string

var html = `<html>
<head>
<script>` + wasm_exec + `</script>
<script>
const go = new Go();
var module = WebAssembly.instantiateStreaming(fetch("hellofront"), go.importObject).then((result) => {
	go.run(result.instance);
});
</script>
</head>
<body>
<h1 id="current"></h1>
<button onclick="GetCurrent()">Load Current</button>
</body>
</html>
`

const storefile = "myfancydatastore.txt"

func readFromStore() Answer {
	b, err := ioutil.ReadFile(storefile)
	if err != nil {
		// do something
	}
	var a Answer
	err = json.Unmarshal(b, &a)
	if err != nil {
		// do something
	}
	return a
}

func writeToStore(a Answer) {
	b, err := json.Marshal(a)
	if err != nil {
		// do something
	}
	ioutil.WriteFile(storefile, b, 0644)
}

func serveIndex(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodGet {
		w.Header().Set("content-type", "text/html; charset=utf-8")
		w.Write([]byte(html))
	}
}

func handler(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodGet {
		w.Header().Set("content-type", "application/json")
		a := readFromStore()
		b, err := json.Marshal(a)
		if err != nil {
			// do something
		}
		w.Write(b)
		a.Current = a.Current + 1
		writeToStore(a)
	}
}

func loadWASM(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodGet {
		w.Write(wasm)
	}
}

func main() {
	writeToStore(Answer{Current: 0})
	mux := http.NewServeMux()
	mux.HandleFunc("/", serveIndex)
	mux.HandleFunc("/current", handler)
	mux.HandleFunc("/hellofront", loadWASM)
	fmt.Println("Starting server on localhost:8000")
	http.ListenAndServe("localhost:8000", mux)
}

Receiver-side Cutoff the third

I guess what I was thinking of in Receiver-side Cutoff is just IRC without bouncers. People can’t continue sending when you’re not connected. Seems like a good idea. Also no GDPR/DSGVO problems, because messages aren’t saved.

AI is not the problem

… Peter Welch wrote

After six or seven years in this professional clink, what people pay software engineers for is their knowledge of what not to do. If my friends and family ask me to build them a website I send them to Squarespace, since it will be much cheaper and probably better than anything I could do for them. We get paid to grasp the ecosystem at large, stay vaguely up to date, and divert ruinous architectural traps before they show up on a quarterly report. Anyone can google the solutions to most of the particular problems we deal with; we get paid to know what to google and how to read the answer.

[…]

The fact that grammatically or syntactically correct semi-nonsense collected from shallow knowledge can displace real world tests of comprehension means we’re not holding ourselves to a particularly high standard. Actual use of ChatGPT for articles or essays or code will produce more of the content that made its output subpar, and achieve little besides accelerating the homogenization of mediocrity.

< Older

Newer >