Dette innlegget handler om et preventivt stresstiltak, i form av en ASMR-stimuleringsenhet, som hjelper kroppen til å følge en mer naturlig rytme. Den har formen til en potteplante, og avgir blant annet fuglekvitter og bekkelyder. Eksempelkode er skrevet i Arguino IDE (C++)
Verden endrer seg med økende frekvens, og den frekvensen økonomien opererer på i dag er, sett fra et historisk/evolusjonsmessig perspektiv, unormal. Effektene av dette må vi mennesker til syvende og sist betale for, gjennom et overstimulert nervesystem, samt følgeeffekter dette kan ha på kroppens andre systemer og funksjoner.
Det finnes flere forebyggende og mitigerende metoder for å håndtere stress. Vanlige metoder for å få løst opp i stramme muskler, få ut stresshormoner og for å berike kroppen med ny luft, er ofte fysisk aktivitet, men som et lite labbprosjekt har jeg funnet på en mer uvanlig, men forebyggende tiltak mot stress.
Bakgrunnen for initiativet er en økt bevissthet knyttet til hvordan det urbane og økonomisk orienterte samfunn ofte bryter med natur og harmoni. Dermed oppstod ideer om hvordan kompensere litt for dette.
Dette innlegget handler nemlig om et forebyggende tiltak, i form av en Autonom sensorisk meridianrespons (ASMR)-stimuleringsenhet, som hjelper kroppen til å følge en mer naturlig rytme ved bruk av en potteplante, naturlyder og kode skrevet i Arduino IDE.
Autonom sensorisk meridianrespons (ASMR) er en opplevelse karakterisert som en statisk-lignende, eller prikkende, følelse mot hud, som typisk starter i hodebunnen for så å bevege seg ned mot nakke og øvre ryggrad. Kilde: Wikipedia.
Ved å for eksempel gi dine ører lyden av harmonisk natur, og en fin liten potteplante i øyesyn, så vil dette kunne bidra til å holde det parasympatiske nervesystemet dominant.
Etter koronapandemien har ASMR blitt et veletablert fenomen i populærkulturen. Det kan kanskje skyldes at flere har måttet tilbringe mer tid innenfor hjemmets fire vegger, og ikke har fått gå ut og oppleve naturen prakt.
Funksjonelt består altså enheten av en visuell komponent form av en fin liten potteplante (kunstig riktig nok), og av en naturlyd som korresponderer til gitt kalenderdag og tid på dagen. Denne versjonen er basert på store statiske lydklipp.
Kort fortalt så fungerer enheten slik at når man kobler den til, så er det første du må gjøre å åpne en laptop eller mobil med WiFi-tilkobling til det nettet du ønsker å koble til. Skriv så inn en IP-adresse i nettleseren og tast inn WiFi-brukernavn + passord og lagre. Når dette er gjort vil enheten koble seg til WiFi-nettet samt hente dato og klokkeslett og forberede en avspilling som passer døgnrytmen. Naturlyd kommer så ut i høyttaleren.
Enheten jeg har laget er basert på en NodeMCU/ESP8266. Denne er så koblet til en liten høyttaler med god kvalitet, gjennom en seriell MP3-modul. Det er en forholdsvis rimelig dings. Koden er skrevet i C++ in Arduino IDE, men man kan også skrive kode for den gjennom en egen Python platform.
Jeg brukte en ordinær USB-plugg som kan kobles til en vanlig mobillader, og enheten benytter altså 5V-driftsspenning. En MP3-modul er koblet til gjennom det serielle grensesnittet til microkontrolleren, f.eks. D0 & D1 til MP3-modulens TX og RX.
Driver til MP3-modulen jeg har brukt kan man finne her: https://github.com/ArtronShop/OPEN-SMART-RedMP3
Ettersom at MP3-modulen støtter avspilling av flere strømmer samtidig, ser jeg på mulighet for avspilling av flere avslappende naturlyder, for eksempel bekker eller dyr, for å kunne gi flere opplevelser og kombinasjon for hver dag som går.
Kode
#include <Time.h> #include <Timezone.h> #include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include <EEPROM.h> #include <NTPClient.h> #include <WiFiUdp.h> #include <SoftwareSerial.h> #include <RedMP3.h> #define RX 5//RX of NodeMCU #define TX 4//TX of NodeMCU MP3 mp3(RX,TX); WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP); // Central European Time (Frankfurt, Paris) TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; // Central European Summer Time TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; // Central European Standard Time Timezone CE(CEST, CET); const int MINUTE = 60000; const int8_t WINTER = 1; const int8_t SPRING = 2; const int8_t SUMMER = 3; const int8_t AUTUMN = 4; const int8_t GONG = 5; int8_t volume = 0x11;//0~0x1e (30 adjustable level) 0x1a struct tm *ptm; unsigned long epochTime; int month_; int hour_; int minute_; int i = 0; int statusCode; String st; String content; //Function Decalration bool testWifi(void); void launchWeb(void); void setupAP(void); //Establishing Local server at port 80 whenever required ESP8266WebServer server(80); void setup() { Serial.begin(115200); //Initialising if(DEBUG)Serial Monitor Serial.println(); Serial.println("Kobler fra wifi"); WiFi.disconnect(); EEPROM.begin(512); //Initialasing EEPROM delay(10); pinMode(LED_BUILTIN, OUTPUT); Serial.println(); Serial.println(); Serial.println("Starter opp"); //---------------------------------------- Read eeprom for ssid and pass Serial.println("Leser EEPROM ssid"); String esid; for (int i = 0; i < 32; ++i) { esid += char(EEPROM.read(i)); } Serial.println(); Serial.print("SSID: "); Serial.println(esid); Serial.println("Leser EEPROM passord"); String epass = ""; for (int i = 32; i < 96; ++i) { epass += char(EEPROM.read(i)); } WiFi.begin(esid.c_str(), epass.c_str()); if (testWifi()) { Serial.println("Tilkoblet."); delay(500);//Requires 500ms to wait for the MP3 module to initialize timeClient.begin(); delay(500); timeClient.update(); epochTime = timeClient.getEpochTime(); return; } else { Serial.println("Slår på Wifi HotSpot"); launchWeb(); setupAP();// Setup HotSpot } Serial.println(); Serial.println("Ventar."); while ((WiFi.status() != WL_CONNECTED)) { Serial.print("."); delay(100); server.handleClient(); } } void loop() { time_t lokaltid = getLocalTime(CE, timeClient.getEpochTime()); ptm = gmtime(&lokaltid); month_ = ptm->tm_mon+1; hour_ = ptm->tm_hour; minute_ = ptm->tm_min; if (hour_ == 0 && minute_ == 0) { // start if (month_ < = 3) { mp3.playWithFileName(WINTER,1); } else if (month_ <= 6) { mp3.playWithFileName(SPRING,1); } else if (month_ <= 9) { mp3.playWithFileName(SUMMER,1); } else if (month_ <= 12) { mp3.playWithFileName(AUTUMN,1); } } mp3.playWithFileName(4,1); Serial.println("."); delay(MINUTE); // refresh every 1 minute } //----------------------------------------------- Fuctions used for WiFi credentials saving and connecting to it which you do not need to change bool testWifi(void) { int c = 0; Serial.println("Venter på at Wifi skal koble seg til"); while ( c < 100 ) { if (WiFi.status() == WL_CONNECTED) { return true; } Serial.print("*"); digitalWrite(LED_BUILTIN, HIGH); delay(250); digitalWrite(LED_BUILTIN, LOW); delay(250); c++; } Serial.println(""); Serial.println("Tilkobling feilet, åpner AP"); return false; } void launchWeb() { Serial.println(""); if (WiFi.status() == WL_CONNECTED) Serial.println("WiFi tilkoblet"); Serial.print("Lokal IP: "); Serial.println(WiFi.localIP()); Serial.print("SoftAP IP: "); Serial.println(WiFi.softAPIP()); createWebServer(); // Start the server server.begin(); Serial.println("Server startet"); } void setupAP(void) { WiFi.mode(WIFI_STA); WiFi.disconnect(); delay(100); int n = WiFi.scanNetworks(); Serial.println("scanning ferdig"); if (n == 0) Serial.println("fant ingen nettverk"); else { Serial.print(n); Serial.println(" nettverk funnet"); for (int i = 0; i < n; ++i) { // Print SSID and RSSI for each network found Serial.print(i + 1); Serial.print(": "); Serial.print(WiFi.SSID(i)); Serial.print(" ("); Serial.print(WiFi.RSSI(i)); Serial.print(")"); Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "*"); delay(10); } } Serial.println(""); st = "<ol>"; for (int i = 0; i < n; ++i) { // Print SSID and RSSI for each network found st += "<li>"; st += WiFi.SSID(i); st += " ("; st += WiFi.RSSI(i); st += ")"; st += (WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "*"; st += "</li>"; } st += "</ol>"; delay(100); WiFi.softAP("naturlyd", ""); Serial.println("Initializing_softap_for_wifi credentials_modification"); launchWeb(); Serial.println("over"); } void createWebServer() { { server.on("/", []() { IPAddress ip = WiFi.softAPIP(); String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]); content = "<!DOCTYPE HTML><html>Sett opp WiFi for naturlyd opplegg:"; content += "<form action=\"/scan\" method=\"POST\"><input type=\"submit\" value=\"scan\"></form>"; content += ipStr; content += "<p>"; content += st; content += "</p><form method='get' action='setting'><label>SSID: </label><input name='ssid' length=32><input name='pass' length=64><input type='submit'></form>"; content += "</html>"; server.send(200, "text/html", content); }); server.on("/scan", []() { //setupAP(); IPAddress ip = WiFi.softAPIP(); String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]); content = "<!DOCTYPE HTML><html>gå tilbake"; server.send(200, "text/html", content); }); server.on("/setting", []() { String qsid = server.arg("ssid"); String qpass = server.arg("pass"); if (qsid.length() > 0 && qpass.length() > 0) { Serial.println("sletter eeprom"); for (int i = 0; i < 96; ++i) { EEPROM.write(i, 0); } Serial.println(qsid); Serial.println(""); Serial.println(qpass); Serial.println(""); Serial.println("skriver eeprom ssid:"); for (int i = 0; i < qsid.length(); ++i) { EEPROM.write(i, qsid[i]); Serial.print("Skreiv: "); Serial.println(qsid[i]); } Serial.println("skriver eeprom passord:"); for (int i = 0; i < qpass.length(); ++i) { EEPROM.write(32 + i, qpass[i]); Serial.print("Wrote: "); Serial.println(qpass[i]); } EEPROM.commit(); content = "{\"Success\":\"skrev til eeprom... reset enhet for å koble til wifi\"}"; statusCode = 200; ESP.reset(); } else { content = "{\"Error\":\"404 not found\"}"; statusCode = 404; Serial.println("Sender 404"); } server.sendHeader("Access-Control-Allow-Origin", "*"); server.send(statusCode, "application/json", content); }); } } /** * * TimeZone related help functions * */ time_t getLocalTime(Timezone tz, time_t utc) { char buf[40]; char m[4]; // temporary storage for month string (DateStrings.cpp uses shared buffer) TimeChangeRule *tcr; // pointer to the time change rule, use to get the TZ abbrev return tz.toLocal(utc, &tcr); }