Încercați instalatorul și un pic de JavaScript pentru a construi o API locală simplă pentru exploatarea evenimentelor de migrenă 🧠💻. Doar o atingere rapidă pe telefonul meu înregistrează acum timpul către un CSV – la îndemână! 📱✅
Motivație
După blogul nostru anterior despre monitorizarea presiunii barometrice, prietenul meu Alec Wong a spus „Nu va fi minunat dacă putem doar să apăsăm un buton și va înregistra un eveniment?”.
În acest caz, motivul înregistrării presiunii barometrice este de a vedea dacă există o legătură între evenimentul migrenă și valorile/schimbarea presiunii barometrice etc. Și da, ar fi minunat dacă putem crea o aplicație de ceva de ceva pentru a face înregistrarea mult mai ușoară!
Există multe modalități de a face acest lucru. Modul în care putem maximiza învățarea în mediul R este să folosim plumber
Pentru a crea o API pentru noi să interacționăm și să înregistrăm evenimentul! Cazul nostru de utilizare este de fapt destul de simplu. Avem nevoie doar de ceva care să înregistreze un timestamp curent atunci când este clic pe un buton. Simplu!
Dar din moment ce nu am folosit niciodată plumber
Înainte, aceasta este o oportunitate excelentă de a o explora! Și, de asemenea, un pic de JavaScript. Din nou, acest blog este mai mult în beneficiul meu, unde servește ca o notă pentru mine. Începem!
Obiective:
Imagine mare
După cum arată imaginea de mai sus, dorim o aplicație pe telefonul nostru care, odată ce a dat clic, va schimba cumva un date de date CSV. Toate acestea pot fi făcute de plumber
Setarea unei API la csv
. Întrucât vreau doar să pot face acest lucru într -o rețea locală a unui dispozitiv diferit (de exemplu, Raspberrypi), nu trebuie să implementăm acest lucru în Digital Ocean sau un server în sine. Îl putem rula în fundal și set systemctl
În cazul în care RPI repornește, indicați -l către 0.0.0.0
Și putem primi/posta prin intermediul IP -ului dispozitivului.
Da, din păcate, acest lucru nu va funcționa dacă nu mai suntem în rețeaua locală, care cel puțin din utilitatea mea, va fi bine. Nu este nevoie să expuneți redirecționarea porturilor. Modul mai sigur ar fi să folosești digitală ocean digital pentru a face acest lucru, astfel încât să nu expuii propriul IP și să deschizi portul publicului. Asta înseamnă și, este posibil să fiți nevoit să plătiți ceva 💰 (de exemplu, 5 $/lună). Poate într -o zi când poate încorpora presiunea barometrică și/sau alte valori
instalator.R
library(plumber) library(readr) file <- "migraine.csv" if (file.exists(file)) { df <- read_csv(file) } else { df <- tibble(date=as.POSIXct(character())) } #* @apiTitle Migraine logger #* @apiDescription A simple API to log migraine events #* Return HTML content #* @get / #* @serializer html function() { # Return HTML code with the log button html_content <- 'Migraine Logger ' return(html_content) } #* logging #* @post /log function(){ date_now <- tibble(date=Sys.time()) df <<- rbind(df,date_now) write_csv(df, "migraine.csv") list(paste0("you have logged ", date_now$date(1), " to migraine.csv")) } #* download data #* @get /download #* @serializer csv function(){ df }
Bine, să explorăm codul unul câte unul. Din nou, ca o notă în beneficiul meu.
Încărcați biblioteci, date de încărcare, metadate
library(plumber) library(readr) file <- "migraine.csv" if (file.exists(file)) { df <- read_csv(file) } else { df <- tibble(date=as.POSIXct(character())) } #* @apiTitle Migraine logger #* @apiDescription A simple API to log migraine events
Cele de mai sus sunt destul de auto-expulzătoare. Indicați -vă spre un fișier, dacă există, citiți -l, dacă nu creați un DataFrame gol. Titlul și descrierea acestei API sunt descrise ca atare.
Să scriem HTML și JavaScript
#* Return HTML content #* @get / #* @serializer html function() { # Return HTML code with the log button html_content <- 'Migraine Logger ' return(html_content) }
- Scheletul #*, mai întâi este comentariul, al doilea este
GET /
(Metoda HTTP), a 3 -a esteTurn this function into HTML output
Serializator. Practic înseamnă dacă mergem lahttp://localhost:8000/
va returna acest html. Acum dacă ne stabilimGET /hello
atunci HTML va arăta și dacă mergeți lahttp://localhost:8000/hello
- Următorul este HTML (fără JavaScript, care este între). Practic, scrieți o rubrică, creați un buton și un rezultat DIV pentru a returna.
- JavaScript:
document.getElementById("submit").onclick
: Cândsubmit
butonul a fost dat clic, rulați funcțiafetch("/log", { method : "post" })
: aceasta este partea în care se va numiPOST /log
Funcție (vezi mai jos) și rulează -l..then(response => response.json())
: Acesta este un lanț de promisiuni. După finalizarea cererii de preluare, acest lucru ia răspunsul de la server și apelează la metoda .json () pe ea, care analizează corpul de răspuns JSON într -un obiect JavaScript. Această metodă returnează, de asemenea, o promisiune care se rezolvă la datele JSON analizate..then(data => { const resultDiv = document.getElementById("result"); resultDiv.textContent = data(0); resultDiv.style.display = "block";})
: Acesta este următorul pas în lanțul de promisiuni. Odată ce JSON este analizat, acesta găsește elementul HTML cu ID -ul „Rezultatul”. Setează conținutul de text pentru a fi primul element din tabloul de date (date (0)). Face ca elementul să fie vizibil prin setarea proprietății sale de afișare CSS la „blocare”.catch(error => { const resultDiv = document.getElementById("result"); resultDiv.textContent = error.message })};
Acest lucru surprinde orice erori care ar putea apărea în timpul funcționării de preluare sau la procesarea răspunsului. Dacă se întâmplă o eroare, găsește elementul HTML cu ID „Rezultat”. Setează conținutul său de text la mesajul de eroare.
Lucrul interesant pe care nu l -am întâlnit este funcția săgeată. response => response.json()
mijloace function(response) { return response.json() }
.
Mai multe funcții API de instalator:
#* logging #* @post /log function(){ date_now <- tibble(date=Sys.time()) df <<- rbind(df,date_now) write_csv(df, "migraine.csv") list(paste0("you have logged ", date_now$date(1), " to migraine.csv")) } #* download data #* @get /download #* @serializer csv function(){ df }
-
POST /log
Funcția este locul în care se întâmplă magia. Când este clic pe butonul, acesta va rula această funcție. Acesta va crea un nou rând cu Timestamp -ul curent și îl va adăuga la DataFrame. Apoi scrie -l lamigraine.csv
.<<-
Operatorul este utilizat pentru a atribui o valoare unei variabile în mediul părinte (în acest caz, mediul global). Acest lucru ne permite să modificămdf
variabilă definită în afara funcției.list(paste0("you have logged ", date_now$date(1), " to migraine.csv"))
va returna un mesaj utilizatorului potrivit căruia evenimentul a fost înregistrat. Aceasta este ceea ce va fi afișat în div cu ID „Rezultat” în HTML. -
GET /download
Funcția este de a descărca datele. Va returna DataFrame ca fișier CSV atunci când accesațihttp://localhost:8000/download
.@serializer csv
Linia îi spune instalatorului să serializeze ieșirea ca fișier CSV.
Ok, hai să o verificăm! Faceți clic pe asta Run API
Buton pentru un test rulat!
Ar trebui să vedem așa ceva. Îl puteți testa prin Swagger UI sau puteți merge la adresa fără __doc__
Pentru a ajunge direct la HTML.
Ura! Funcționează, local … acum să vedem dacă funcționează dacă este pe un alt dispozitiv.
Cum să -l rulezi?
- Transfer
plumber.R
sau orice fișier pe care l -ați salvat, la dispozitivul la alegere. - Instalați pachete, desigur
- Apoi rulați următorul cod
Rscript -e "pr <- plumber::plumb('plumber.R'); pr |> pr_run(port=8000,host='0.0.0.0')"
Ce face, va rula API -ul instalatorului. Și utilizați un dispozitiv diferit în aceeași rețea, apoi accesați http://your-local-device-ip:8000/
Și ar trebui să vezi ceva de genul următoarelor
Ura! Funcționează! Acum, să ne asigurăm că îl rulăm în fundal și dacă RPI repornește, va re-rula scriptul folosind systemctl
. Toate codul de mai jos trebuie să fie rulat bash
sudo nano /etc/systemd/system/migraine-logger.service
Lipiți acest lucru în migrenă-logger.service
(Unit) Description=Migraine Logger Plumber API After=network.target (Service) Type=simple User=pi WorkingDirectory=/path/to/your/app ExecStart=/usr/bin/Rscript -e "pr <- plumber::plumb('plumber.R'); pr |> pr_run(port=8000, host='0.0.0.0')" Restart=on-failure RestartSec=5 (Install) WantedBy=multi-user.target
- Schimba
/path/to/your/app
în directorul undeplumber.R
Fișierul este localizat.
Activați, începeți, verificați starea
sudo systemctl enable migraine-logger.service sudo systemctl start migraine-logger.service sudo systemctl status migraine-logger.service
Hurray !!!
Un singur clic pe iOS?
Utilizați browserul dvs. pe iOS pentru a merge la IP -ul și portul dispozitivului dvs. http://192.168.1.11:8000
apoi faceți clic pe Share și creați ecranul de scurtă durată, așa cum este așa
Apoi, puteți avea o scurtătură pe dispozitivul dvs. iOS care va deschide aplicația și va face clic pe butonul pentru dvs.!
Oportunități de îmbunătățire
- Acest lucru funcționează numai dacă sunteți în rețeaua locală, puteți extinde acest lucru la picătura digitală ocean, mai ales dacă adăugăm mai multe caracteristici (de exemplu, postați jurnal vechi dacă am fi uitat să înregistrăm una, să arătăm 10 ultime date, să arătăm date barometrice etc.)
- trebuie să înveți mai multe node.js/javascript, chiar mi -a plăcut să folosești pozitron și
Code Runner
pentru a putea apela rapidnode
și rulați întregul script pe consolă - trebuie să afli mai multe despre
plumber
de exemplu, cum să -l implemezi în oceanul digital - O parte Python la care am putea traduce este FastApi, trebuie să învățăm și asta, dar implementarea și structura codului ar trebui să fie destul de similară
Lecții învățate
- Am învățat câteva API simple pentru instalații de instalație
- Am învățat câteva javascript simplu, a descoperit că acest potențial major pentru proiectele viitoare.
- Învăţat
systemctl
Dacă vă place acest articol: