1. Introduction
My apartment building is using an automated system to unlock the front door. We have to use a proprietary app (AlphaTouch) and unlock the door by sliding a toggle. It takes time because the app is slow. Let’s find a way to make this easier!
Goal
Let’s have an iOS Shortcut instead! I will just have to press it on my phone home page.
It’s possible to create a Shortcut that execute a http request
I would like to have a simple endpoint (http://myendpoint.something/unlock_door
)
2. Let’s find a way to open my door without the App
Alphatouch provides an APP and a Website.
When we open the website, we can see a “Trigger Open Door” button. Let’s click on it and check the network calls
We can see that clicking this button fire a network call that I suppose open the door (the url is .../trigger_pin.php
)
Before going further, let’s copy this command call as cURL (using the DevTools again) and let’s fire this CURL call again while I am in front of my door.
Success! The door open!
This network call contains tons of headers + query params + a body. We could just fire it from our iOS shortcut, but let’s make things easier and play with serverless functions instead!
3. A Go program triggering our cURL code
I chose to use Go because this is what I am using every day. We could use Python or JS, both are supported by serverless functions and may be faster to write, but I like Go syntax.
Let’s create a new folder/repository for our program. First, we need a simple function that triggers our http call.
To convert our complex cURL call to Go code, we can use this website: https://mholt.github.io/curl-to-go/
package open_door_entry
import (
"encoding/json"
"errors"
"io"
"net/http"
"strings"
)
// By looking at the response from the HTTP Call, we can see that we get a JSON object contain a "success" variable
// Let's declare this object in Go in order to parse the reponse and monitor error/success
// It's easy to do with Jetbrains IDE, especially Goland. You can do "CMD+N" and "Type from JSON"
type openDoorResponse struct {
Success bool `json:"success"`
}
func createReq() (*http.Request, error) {
// generate this code using https://mholt.github.io/curl-to-go/
req, err := ...
return req, nil
}
// the function that will open our Door.
func OpenDoor() error {
req, err := createReq()
if err != nil {
return err
}
// let's execute the query
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
if resp.StatusCode != 200 {
return errors.New(resp.Status)
}
// reading the body...
defer resp.Body.Close()
b, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
// parsing the body
var openDoorResp openDoorResponse
err = json.Unmarshal(b, &openDoorResp)
if err != nil {
return err
}
// Checking response success
if openDoorResp.Success {
return nil
}
return errors.New("error success=false from response")
}
4. Let’s deploy this to Vercel
This piece of code is very small and fast to execute (~1sec, most of the time is spent in the http call) I plan to trigger this ~5 times a day (everytime I want to open my front door).
I found that the cheapest way to host this is to use serverless tech.
There are multiple offerings here, the most popular are:
- AWS with Lambda
- GCP with Cloud Functions
I heard good things about Vercel and I wanted to try them for a while. They are supposed to deliver the best dev experience.
Let’s try this out!
After looking at their website, they offer Serverless Functions.
As a part of their Free plan, you have access to:
- 100GB-Hours
- 10s function timeout
That’s perfect for our use case! Let’s set this up.
- Create an account on Vercel
- Install their CLI (
yarn global add vercel
) (you will need nodejs + yarn installed for this) - Login with their CLI
vercel login
- Create an empty
package.json
at the root of your folder/repository (echo '{}' > package.json
) - Link this repository to your vercel account
vercel link
(you can delete thepackage.json
after this step!) - Then let’s refactor our repository to support their architecture! We just need a
api
folder at the root! - This
api
folder will contain all our “functions entrypoint”
Every function with a specific signature in this folder will be a Serverless Function. Let’s create ours!
// api/open_door.go
package handler
import (
"net/http"
// the func we just made before
"dimitriwyzlic.com/serverless_functions/internal/open_door_entry"
)
// Any function using this signature will be a Serverless Func
func OpenDoor(w http.ResponseWriter, r *http.Request) {
err := open_door_entry.OpenDoor()
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
} else {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Success!"))
}
}
- Once this is done, just run
vercel dev
- You will be able to query
localhost:3000/api/[your_file_name_without_extension]
- If it’s working, just run
vercel prod
- Now, go to the Vercel website and select your project. Get your prod url by looking at the following image
- Click on
Logs
then on the left panel, expandFunction
and select your function. - Open a new tab and call
[your prod url]/api/open_door
(replaceopen_door
with whatever your file underapi
is named) - If you go back to the previous tab containing your logs, you should see your call in real time!
5. Conclusion
Congratulation! You now have a working Go function hosted on the cloud that should be free forever!
I wanted to have an iOS shortcut that will allow me to open my door. The last step is just to create a shortcut with the Open URL
or Get contents of
action!