Arduino-övervakad ringklocka: kretskort färdigt!

Berätta om dina pågående projekt.
Nille86
Inlägg: 65
Blev medlem: 13 april 2019, 13:10:49

Re: Arduino-övervakad ringklocka

Inlägg av Nille86 »

Jag har en mottagare kopplad till en Raspberry pi. Jag har testat förbindelsen tidigare med ett enkelt Hello World-exempel men nu var jag mest intresserad av att se om min koppling fungerade, därför hade jag inte satt igång mottagaren ens.

I första versionen ska ringklockan endast sända information men i version 2 ska kommunikationen vara dubbelriktad. Du får gärna lägga upp din kod!
Alex_Holo
Inlägg: 69
Blev medlem: 21 november 2010, 18:40:50

Re: Arduino-övervakad ringklocka

Inlägg av Alex_Holo »

Har förra veckan gått igenom samma resa för att få igång mina nya nRF24L01 moduler. Tog mig mycket googlande, så här är lite tips på vägen (inte testat alla, men lite sammanfattning av allt jag läst).

-Modulen har inbygg mottagningsbekräftelse! Finns även exempel i nedanstående länk där du förbereder extra data att skicka med i bekräftelsen, på så sätt slipper du byta TX/RX och öppna dubbla kanaler för modulerna. Funkar mycket bra för mig när min master begär data genom att bara skicka en "ping" till mina slavar, som svarar (med inbyggda bekräftelsen) och sen skickar med den data jag behöver.

-Läs igenom den här tråden och testa hans exempelkoder. Funkar mycket bra! https://forum.arduino.cc/index.php?topic=421081.0

-Se till att du kör på låg effekt, om du kan ha modulerna nära, när du testar.

Kod: Markera allt

radio.setPALevel(RF24_PA_MIN);
Annars kontrollera att du har bra strömförsörjning och sätt en konding vid matningen så nära modulen som möjligt. Många har problem med spänningen och flera säger att 3.3V från arduinons inbyggda regulator inte räcker till! Jag tappar räckvidden på låg effekt redan efter 6-7 meter. Kanske överväga den stora modellen med extern antenn annars?

-Dessa moduler gillar inte minusgrader. Såg ut som på bilden att du testar utomhus med risk för kyla. Ska gå att få dom att funka bra i kyla om man byter en konding till större värde (och ev annan typ).

-Vid mina första tester känns det ibland som modulerna hamnar i osynk/hänger sig. Vet inte vad det beror på, kan ev vara glapp i breadbordet. Jag funderar på någon form av watchdog eller övervakning att mina slavar tar emot data inom en given tid, annars en omstart av arduinon. Kanske lite svårare på din applikation, men finns ju inget som hindrar att din ringklocka skickar en ping att den lever på lämpligt tidsintervall.

-Det finns två olika bibliotek ute med samma namn! Ett av dessa är äldre och funkar dåligt. Radera ALLT som har med detta att göra, om du inte är 100% säker på att du har det senaste!
Står mer info i tidigare länk och han länkar till det fungerade biblioteket i första inlägget.

Lycka till :)
Nille86
Inlägg: 65
Blev medlem: 13 april 2019, 13:10:49

Re: Arduino-övervakad ringklocka

Inlägg av Nille86 »

Tack för trevlig info och trevliga länkar! Jag har felsökt i några timmar nu och kan konstatera att jag lyckades döda min ena modul. Troligtvis har jag råkat komma åt med för hög spänning i samband med att jag kopplade in arduinon uppe vid ringklockan. Jag kopplade dumt nog inte ur modulen för att "spara tid". Det gick ju inte så bra med tanke på att jag fick felsöka i två timmar för att hitta felet :(.

Arduinon låser sig helt och hållet när man kör radio.write(). Jag trodde att det berodde på att den inte fick en mottagningskvittens men det beror på att modulen är död.. Med en ny modul på plats fungerar kommunikationen som den ska. Jag hittade även lite exempelkod som matar ut all information om den anslutna modulen, klistrat nedan.

Bifogar även två utskrifter på min fungerande modul och min nu brända modul.

Jag ska undersöka vilket bibliotek det är jag använder. Hittade tidigare idag att i Arduino IDE låg det ett antal exempel långt ner i listan under RF24 som verkar intressanta att studera. Jag ska börja koda lite på sändaren/mottagaren, på något sätt vill jag notifera en android-app om att någon har plingat på dörren.

Kod: Markera allt

#include <SPI.h>
#include <RF24.h>
#include "printf.h"

//
// Hardware configuration
//

// Configure nRF24L01 radio module on SPI bus plus pins 8 for CE & 9 for CS
// arguments are (ce, cs)

RF24 radio(9,10);

//
// Set transmit and receive addresses
//

const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

void setup(void)
{

  Serial.begin(9600);
  printf_begin();
  printf("\n\rTest connection to modules\n\r");

  //
  // Setup and configure rf radio
  //

  radio.begin();
 
  // Set the TX and RX addreses in the module
 
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1,pipes[1]);
 

  // radio.setDataRate( RF24_2MBPS ) ;
  // radio.setPALevel( RF24_PA_MAX ) ;
  radio.enableDynamicPayloads() ;
  radio.setAutoAck( true ) ;
  radio.powerUp() ;
  radio.startListening();

  //
  // Print out the configuration of the rf unit for debugging
  //

  radio.printDetails();
}

void loop(void)
{
}
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Alex_Holo
Inlägg: 69
Blev medlem: 21 november 2010, 18:40:50

Re: Arduino-övervakad ringklocka

Inlägg av Alex_Holo »

Kul att det funkar och tack för koden hur man får ut modulernas status, den ska jag testa! :D

Du får gärna återkomma om du får din app lösning att fungera, då det är precis åt det hållet jag också ska!

Har beställt en ESP8266 wifi modul som jag ännu inte fått igång. Därefter har jag kollat på appen Pushover (50kr i engångskostnad), verkade vara den bästa/enklaste att komma ingång med för att få notiser i telefonen. Fanns även färdigt bibliotek för arduino.
Nille86
Inlägg: 65
Blev medlem: 13 april 2019, 13:10:49

Re: Arduino-övervakad ringklocka

Inlägg av Nille86 »

Jag läser för fullt om googles "Firebase" som verkar vara nyckeln till att skicka meddelanden till mobilen. Jag lyckades precis köra ett curl-kommando som genererade en notifiering i min emulerade android-app. En bra början alltså :).

Jag vill helst undvika "smarta tjänster" som gör jobbet åt mig då det jag vill lära mig är hur programmeringen/kommunikationen fungerar. Att jag gör min ringklocka trådlös är egentligen bara för att ha något att göra på vägen om du förstår vad jag menar. För mig är resan det roliga och att då använda en färdig tjänst som gör allt jobbet åt mig gör att allt det roliga försvinner. Jag har dock full förståelse för att andra personer kan ha andra mål med applikationerna/komponenterna de bygger.

Jag ska försöka skriva ett längre inlägg ikväll där jag går igenom de steg jag gått igenom så här långt, risken är annars att jag glömmer det igen :)
Nille86
Inlägg: 65
Blev medlem: 13 april 2019, 13:10:49

Re: Arduino-övervakad ringklocka- Androidnotifiering m. fire

Inlägg av Nille86 »

Jag ska försöka sammanfatta mina resultat så här långt. Tanken är att jag kanske förstår det lite bättre som jag blir tvungen att försöka förklara hur jag har gjort. Och med lite tur kanske någon annan medlem med mer erfarenhet komma med bra synpunkter.

Nåväl.. Jag hittade relativt snabbt till "Firebase" som är en tjänst från Google där man bland annat kan lägga upp en databas online som kan läsas/skrivas på några olika sätt. Det finns även något som heter "Cloud messaging" som kan användas för att skicka notiser till Androidtelefoner (och iphone?). Firebase verkar vara BETYDLIGT större än så men jag är för stunden endast intresserad av "Cloud messaging".

Jag startade upp Android Studio och fick ladda ner ett gäng uppdateringar eftersom jag inte haft det igång sedan i december.
Jag körde öppnade ett helt nytt projekt och valde en enkel "Empty activity" som mall, programmet fick heta doorbell.

Därefter registrerade jag mig på https://firebase.google.com/ och följde den här guiden: https://firebase.google.com/docs/android/setup,

Jag hade en del bekymmer med att läsa ut applikationens Token som behövs för att kunna skicka en notifikation. Den kod som till sist fungerade är klistrad längre ner.
Applikationens Token kan då utläsas i "logcat" när man väljer att titta på debug-meddelanden.

Min rad såg ut ungefär så här:
2019-04-25 21:37:23.472 22815-22815/com.example.db2 D/tkn: InstanceID Token: fubDjgnTXtg:APA91bGPSIKj-ZLj2WM8pf6ATXp1oVP3nvwOi7hAV24NoczsqWLuuiE7ugENNQFcprvMdoSJWPMt5HM4_WBmc6bVyZT6FIz7QcY-YiVsMjEdd_6rTOBS_9DsB8MKiMcWQsLquF273

Det fungerade utan problem att skicka en notis till min telefon från Firebasehemsidan men eftersom jag vill kunna skicka notisen från min Raspberry Pi så sökte jag vidare efter hur man kan skicka från en egen enhet.

Efter en hel del försök lyckades jag att få fram ett meddelande med hjälp av Curl.
Jag letade länge efter den nyckel som anges efter key= och hittade den till sist inne på kontrollpanelen för mitt projekt på firebase.Under "Cloud messaging" finns en "Server Key" som ska fyllas i efter key=.

Curlkommandot som skickade notfikationen:

Kod: Markera allt

curl -X POST --header "Authorization: key=AAAAdf1aBrk:APA91bEX50_DEVjQ4wMPvZqBoe4-1PcI2wzc2z-6hHd4XJX7DfXxrvFVStXwcDgG0Lx6RfMogTEhl6hUtQn4OCGqrxarbOxARru2mylY1P0aGpDtRywHVmM-CzutHP6s_eqVnJxSPd8w" \
    --Header "Content-Type: application/json" \
    https://fcm.googleapis.com/fcm/send \
    -d "{\"to\":\"dMJTlswMZY0:APA91bHPl8dZ-6V25mlTDSytfDRm65fBUeszygEqy30-hSbj9kTvb6qzjUly9Jl0yXGhf10B3vGjZTP24ra4eKWCyDlQPwec5lQYXKALeSvTo0gOHNjWpIVDO35wrHayyezDH2hwl1tq\",\"notification\":{\"body\":\"HELLO\"},\"priority\":10}"

Javakod för att hämta ut applikationens Token.

Kod: Markera allt

        FirebaseInstanceId.getInstance().getInstanceId()
                .addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
                    @Override
                    public void onComplete(@NonNull Task<InstanceIdResult> task) {
                        if (!task.isSuccessful()) {
                            Log.w("tkn", "getInstanceId failed", task.getException());
                            return;
                        }

                        // Get new Instance ID token
                        String token = task.getResult().getToken();

                        // Log
                        String msg = getString(R.string.msg_token_fmt, token);
                        Log.d("tkn", msg);
                    }
                });

Det återstår fortfarande en hel del:
1. Jag vill lära mig mer om hur JSON, Curl och REST-api:t fungerar
2. Jag vill försöka använda libcurl i C++ för att bygga HTTP-paketet, det kommer nog att kräva en hel del research då jag inte har jättebra koll på C++.
3. På något sätt ska det gå att autentisera klienterna. Raspberryn ska läsa från databasen och plinga i ringklockan om telefonen skrivit till databasen. Telefonen som har skrivrättigheter behöver autentiseras på något sätt.
Nille86
Inlägg: 65
Blev medlem: 13 april 2019, 13:10:49

Re: Arduino-övervakad ringklocka- Androidnotifiering m. fire

Inlägg av Nille86 »

Här kommer en liten uppdatering på mina framgångar med libcurl och notifiering av en android-telefon! Jag tog bort mitt inlägg som handlade om val av transistor och återkommer till det ämnet lite senare.

Libcurl kan användas i både C och C++ för att "bygga" HTML-paket (går även att bygga för andra protokoll).

Det som är nödvändigt att få med för att skicka en notifiering via firebase är följande:
En HEADER som anger formatet: "application/json"
En annan HEADER som anger din servernyckel: "Authorization: key=xXxXxXxXxXx" (byt mot den nyckel som hittas i firebase-console")
Data-paketet som utformas enligt googles önskemål:

to: Mobilens TOKEN. Det finns även stöd för att sända till flera enheter samtidigt.
notification{
title: Titel
body: Meddelande
priority: Prioritet
}

Det finns mer att läsa på https://firebase.google.com/docs/refere ... s.messages men för mina ändamål just nu räcker ovanstånde gott.

den C/C++-kod som jag använder mig av är ett hopkok av libcurls egna exempel tillsammans med lite exempel från Firebase. Det finns mycket mer att göra för att snygga upp det. Det verkar finnas gott om bibliotek för att bygga snygga JSON-paket men det är mer än vad jag behöver just nu. Se kod klistrad i slutet.

För att installera libcurl på Raspberryn körde jag bara: "sudo apt-get install libcurl4-openssl-dev"
Källkoden sparade jag i en fil som hette test.cpp
Därefter kompilerade jag med: "g++ test.cpp -o notifiera -lcurl"
programmet kan därefter köras med ./notifiera och då plingar det i mobilen!

Nu kan jag relativt enkelt integrera radiomottagaren NRF24L01 tillsammans med notiferingen i samma program som då alltid kan vara igång på raspberryn.

Jag kommer att ta en liten på paus från mjukvarubiten och inrikta mig på att lära mig lödning (inte lödat sedan gymnasiet för över 15 år sedan. Planen är att löda ett provkort med alla komponenterna och sen gå på mjukvaran igen när det är färdigttestat.

Kod: Markera allt

#include <stdio.h>
#include <curl/curl.h>
 
int main(void)
{
  CURL *curl;
  CURLcode res;
 
  /* In windows, this will init the winsock stuff */ 
  curl_global_init(CURL_GLOBAL_ALL);
 
  /* get a curl handle */ 
  curl = curl_easy_init();
  if(curl) {

struct curl_slist *chunk = NULL;

    /* Add a custom header */ 
    chunk = curl_slist_append(chunk, "Authorization: key=AAAAdf1aBrk:APA91bEX50wEVjQ4QMPvZqBoe4-1PcI2wzc2z-6hwHf4XJX7DfXxrvFVStXwcDgbdfG0L66RfMogTEhl6hUtQn4OCGqrxarbOxARru2mylY1P0aGpDtRywHVmM-CzutHP6s_eqVnJxSPd8w");

chunk = curl_slist_append(chunk, "Content-Type: application/json");

    /* First set the URL that is about to receive our POST. This URL can
       just as well be a https:// URL if that is what should receive the
       data. */ 
    curl_easy_setopt(curl, CURLOPT_URL, "https://fcm.googleapis.com/fcm/send");
    /* set our custom set of headers */ 
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);

/* Now specify the POST data */ 
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"to\":\"dhw7K_YHaBU:AsPA91bFId0jwUmoFgm7WV7EO22Le0yqXHTPklw5009MLhk9e-cBI_cap0KMcmgr6kXGLn7xp8mpaZ-McFq5ey2XHtpSlgjqP2fisRFyZlyjIK3Nfm09ZI2pke_4uCNOIxIGLBFV-y8q_UX6_\",\"notification\":{\"body\":\"HELLO\"},\"priority\":10}");
 
    /* Perform the request, res will get the return code */ 
    res = curl_easy_perform(curl);
    /* Check for errors */ 
    if(res != CURLE_OK)
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
              curl_easy_strerror(res));
 
    /* always cleanup */ 
    curl_easy_cleanup(curl);
  }
  curl_global_cleanup();
  return 0;
}
Nille86
Inlägg: 65
Blev medlem: 13 april 2019, 13:10:49

Re: Arduino-övervakad ringklocka- Androidnotifiering m. fire

Inlägg av Nille86 »

Jag kunde inte helt släppa kodandet. Satt med mobilen och sökte på info om att streama information om databasen ändras istället för att använda polling med några sekunders mellanrum. Det var inte helt enkelt att hitta när jag inte visste exakt vilka sökord jag skulle använda men till sist landade jag på googles egna sidor: https://firebase.google.com/docs/refere ... -streaming.

Där står att man som header ska skicka "Accept:text/event-stream" och att googles server då kommer att hålla liv i anslutningen och skicka information om databasposten förändras. Se min bild för exempel på hur det kan se ut.

Curl-kommandot som jag kör är: curl -v -H "Accept:text/event-stream" https://ringklocka-ee170.firebaseio.com/ring.json"
ring.json är en post i min databas som innehåller variabeln "value". value kan vara true eller false.

Med jämna mellanrum pingar google för att visa att anslutningen lever. Om jag ändrar värdet i databasen inne i firebase-konsolen syns det direkt i Curl som körs i terminalen. Det borde vara en enkel match att koda lyssnaren i C/C++ med libcurl och överföra signalen till min arduino som då ringer i ringklockan.

Mobiltelefonen behöver skrivrättigheter till databasen när jag ska ringa i dörrklockan och då behöver jag få autentisering att fungera. Det finns gott om guider men jag tycker Android-progammering är rörigt så det blir nog något att bita i.

Jag har för övrigt precis börjat använda KiCad och det är verkligen sjukt roligt att sitta i PCB-editorn och krympa ner kretskortet så att det blir så litet som möjligt. Jag har aldrig någonsin ritat kretskort tidigare så just nu ritar jag endast för att det är roligt, det skulle troligtvis inte gå att beställa korten då jag inte ställt in korrekta mått från en tillverkare. Jag kommer i vilket fall inte att beställa kretskort förrän jag har lödat min prototyp på breadboard. Någon som har bra tips på en bra guide för att designa kretskort?
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
BJ
Inlägg: 8185
Blev medlem: 11 april 2007, 08:14:53
Ort: En_stad

Re: Arduino-övervakad ringklocka

Inlägg av BJ »

Nille86 skrev:Även om det inte är aktuellt precis just nu
funderar jag en del över vad man ska använda för
experimentkort, hela banor, ensamma öar eller 3-och-3?
Jag har inte lödat sedan gymnasiet för cirka 15 år sedan
så vad är lättast att lära sig på?
Vet inte vad du tycker, men jag tycker att dom med
banor är lättast. Då kan man ju välja själv hur långa
man vill ha dom, och var dom ska börja och sluta,
genom att kapa dom med t.ex. ett borr.
Nille86
Inlägg: 65
Blev medlem: 13 april 2019, 13:10:49

Re: Arduino-övervakad ringklocka: Lödning experimentkort!

Inlägg av Nille86 »

Igår kom äntligen alla mina komponenter som jag beställt. Jag har sedan början på april handlat allting som behövs för att komma igång med att löda mina egna kort. Jag beställde en lödstation från AliExpress(KSGER T12), lödtenn från en f.d. kollega, komponenter från electrokit och nu har jag allting jag behöver för att börja löda.

Senast jag lödde var i gymnasiset för dryft 15 år sedan och vad jag minns från den tiden så gick det inget vidare alls. Nu finns tack och lov youtube och jag har spenderat många kvällar med att titta på lödningsvideos :D .

Jag beställde experimentkort med både banor och ensamma öar och jag valde till sist att göra mitt första kort på ensamma öar. Det gick ganska lätt att placera ut komponenter i början men sen körde jag fast vid några tillfällen och fick backa tillbaka och flytta någon komponent som hamnat fel. När jag skulle provköra för första gången med ett 9V-batteri hände absolut ingenting och efter lite felsökning konstaterade jag att jag försökte mata min arduino med GND samt GND. Efter en liten omlödning tändes dioderna på arduinon, framgång!

Efter att jag konstaterat att spänningsmatning och kommunikationen med NRF24L01-modulen fungerade fortsatte jag idag med att löda fast optokopplare och övriga komponenter som känner av när någon trycker på ringklockan. Spänd av förväntan testade jag att koppla in mig på ringklockan för att köra skarpt läge. Spänningsmatningen fungerade men den kände inte av några knapptryck. Efter en stunds googlande gissar jag att felet beror på hur jag kopplat transistorn i optokopplaren. Jag har kopplat 5V -> Kollektor, Emitter -> 1500ohm -> GND. Signalen till arduinon tog jag ut på Emittern. Jag har inte riktigt förstått transistorer men nu har jag iaf kopplat om trådarna så att transistorn "drar strömmen" genom motståndet istället för tvärtom, dvs transistorns Emitter är direkt ansluten till jord och motståndet fick flytta till Kollektorn istället. Kretskortet sitter på plats vid ringklockan och verkar fungera som det är tänkt!

Jag lödde in en snygg anslutning där min NRF24L01 skulle placeras men när skulle provköra kommunikationen stötte jag på bekymmer. Det enda läget som den lyckades skicka iväg paket i var med lägsta signalstyrkan (RF24_PA_LOW). Högre signalstyrka såsom HIGH eller MAX innebar att inte ett enda paket kom fram! När jag har labbat med korten tidigare har jag kört både sändare och mottagare på MAX. Nu har jag dessutom en 10uF kondensator på både sändare och mottagare!

Jag har läst en del, bland annat här på forumet, om störningar på trådlösa signaler och valde därför att koppla modulen med kopplingstrådar som gjorde att den inte satt direkt ovanpå mitt kretskort och då började det att fungera mycket bättre!. Jag vet inte om det är att signalen "förstördes" av att den satt så nära kretskortet eller om den på något sätt "förbättras" av att kopplingstrådarna fungerar som antenner?

Nu ska jag programmera färdigt min raspberry så att signalen skickas vidare till min mobil och därefter är fas 1 färdig. Fas 2 innbär att jag ska löda på lite fler komponenter så att jag även kan plinga i ringklockan från min mobil, dvs tvåvägs-kommunikation. To be continued....

Skriv gärna vad ni tycker om mina lödningar, hur kan jag göra det bättre?
Vad kan problemen med den trådlösa kommunikationen bero på?
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Nille86
Inlägg: 65
Blev medlem: 13 april 2019, 13:10:49

Re: Arduino-övervakad ringklocka: Lödning experimentkort!

Inlägg av Nille86 »

Dags för en lägesuppdatering! Version 1.0 av ringklockeplingaren är färdig och driftsatt. Det har varit väldigt lärorikt även om jag bara skrapat på ytan på flera områden.
Jag skrev om koden för Arduino-enheten i morse så att den går ner i energisparläge och vaknar på extern interrupt från antingen ringklockan(pin 2) eller inkommande meddelande på NRF24L01(pin 3).

Min android-app kan fortfarande förbättras, jag är inte något vidare på UI-design :). Men den gör vad den ska i alla fall. Man måste vara inloggad för att kunna ringa i klockan, jag har valt att godkänna inloggning via Google-konto så det görs i appen om man skulle vara utloggad. Därefter kan man trycka på knappen "PLINGPLONG" och efter en stund ringer det i ringklockan. I status-rutan kan man avsläsa om meddelandet gick fram till ringklockan eller om sändningen misslyckades.

När man trycker på ringklockan skickas en notifikation till min mobil med en timestamp. I framtiden funderar jag på att lägga till en rullista som sparar alla historiska ringningar.

Jag tycker att programmet i Raspberryn var absolut svårast att skriva. Jag programmerade lite i C för 10+ år sedan och skrev en del i JAVA förra året(körde bland annat Advent of Code). RF24 som är biblioteket för NRF24L01 är gjort skrivet i C++ och däför valde jag att skriva all kod i C++. Min känsla är att C++ är en kombination av de svåraste begreppen från C och JAVA. Jag har haft rejäla bekymmer med kodandet och det blir inte bättre av att libcurl som jag använder för att kommunicera med databasen är skrivet i C men accepterar C++ till viss del. En erfaren C++-kodare har nog en och annan synpunkt på min kod gissar jag. Jag överväger att skriva om allting i JAVA som har ett betydligt bättre stöd för firebase-kommunikation eftersom jag behärskar JAVA mycket bättre.

Nedan kommer koden till alla tre enheter, kanske finns det snuttar som andra kan ha nytta av?
Jag sitter i kicad och ritar på ett kort som jag tänker beställa från någon billig leverantör, det blir avslutningen på projektet. Jag har fler saker jag vill bygga så det kommer nog en tråd till inom kort.

Kod: Markera allt

#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include <unistd.h>
#include <iostream>
#include <stdlib.h>
#include <RF24/RF24.h>
#include <time.h>  
#include <chrono>
#include <thread>
#include <functional>
#include <ctime>
#include <sstream>
#include <iomanip>
#include <string> 

// Ställ in parametrar för radio vid uppstart
RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
const uint64_t pipes[2] = {0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL};
static char send_payload[] = "pling";

// sending notification
CURL *curl;
// checking status
CURL *curl2;
// ACK plinkplong
CURL *curl3;

std::string readBuffer;

CURLcode res;
/* Add a custom header */
struct curl_slist *chunk = NULL;

/* Hjälpfunktion för att infoga datum/tid i notifiering */
std::string notification() {
    auto now = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(now);

    std::stringstream ss;
    ss << "{\"to\":\"dhw7K_YHaBU:APA...K3Nfm09ZI2pke_4uCNOIxIGLBFV-y8q_UX6_\",\"notification\":{\"body\":\"DINGDONG ";
    ss << std::put_time(std::localtime(&in_time_t), "%d/%m %X ");
    ss << "\"},\"priority\":10}";

    return ss.str();
}

/* Hjälpfunktion till libcurl */
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    ((std::string*)userp)->append((char*) contents, size * nmemb);
    return size * nmemb;
}

// Körs en gång endast, när programmet startar
void setup(void) {
    radio.begin();
    radio.setRetries(15, 15);
    radio.setPALevel(RF24_PA_MAX);
    radio.openWritingPipe(pipes[1]);
    radio.openReadingPipe(1, pipes[0]);
    radio.setChannel(108);
    radio.startListening();

    // Skicka notifiering - POST
    chunk = curl_slist_append(chunk, "Authorization: key=AAAAdf1aBrk:APA91b...mylY1P0aGpDtRywHVmM-CzutHP6s_eqVnJxSPd8w");
    chunk = curl_slist_append(chunk, "Content-Type: application/json");
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "https://fcm.googleapis.com/fcm/send");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
    }

    // Läs status på ringklocka - GET
    curl2 = curl_easy_init();
    if (curl2) {
        curl_easy_setopt(curl2, CURLOPT_URL, "https://ringklocka-ee170.firebaseio.com/ring/status.json");
        curl_easy_setopt(curl2, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl2, CURLOPT_WRITEDATA, &readBuffer);
    }

    // Uppdatera värde på ringklocka - PATCH
    curl3 = curl_easy_init();
    if (curl3) {
        curl_easy_setopt(curl3, CURLOPT_URL, "https://ringklocka-ee170.firebaseio.com/ring.json?auth=rxcgZ6TXilcSSHNnsY...gcbAeDB");
        curl_easy_setopt(curl3, CURLOPT_CUSTOMREQUEST, "PATCH");
    }
}

void timer_start(std::function<void(void) > func, unsigned int interval) {
    std::thread([func, interval]() {
        while (true) {
            auto x = std::chrono::steady_clock::now() + std::chrono::milliseconds(interval);
            func();
            std::this_thread::sleep_until(x);
        }
    }).detach();
}

// kontrollera om RING/STATUS. Triggas av funktionen timer_start med jämna intervall
void check_firebase() {
    std::cout << "Checking database value..." << std::endl;
    if (curl2) {
        res = curl_easy_perform(curl2);
        /* Check for errors */
        if (res != CURLE_OK) {
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
        }
        std::cout << readBuffer << std::endl;
        if (readBuffer == "\"TRUE\"") {
            std::cout << "PLING PLONG!!" << std::endl;
            radio.stopListening();

            if (radio.write(send_payload, 5)) {
                if (curl3) {
                    curl_easy_setopt(curl3, CURLOPT_POSTFIELDS, "{ \"status\": \"DELIVERED\" }");
                    res = curl_easy_perform(curl3);
                    std::cout << "\n";
                }
            } else {
                if (curl3) {
                    curl_easy_setopt(curl3, CURLOPT_POSTFIELDS, "{ \"status\": \"NO ACK. FROM NRF24L01+\" }");
                    res = curl_easy_perform(curl3);
                    std::cout << "\n";
                }
            }

            radio.startListening();

        } else if (readBuffer == "\"DELIVERED\"" || readBuffer == "\"NO ACK. FROM NRF24L01+\"") {
            if (curl3) {
                curl_easy_setopt(curl3, CURLOPT_POSTFIELDS, "{ \"status\": \"READY\" }");
                res = curl_easy_perform(curl3);
                std::cout << "\n";
            }
        } else {
            std::cout << "FALSE" << std::endl;
        }
        readBuffer.clear();
    }
}

int main(void) {
    setup();
    timer_start(check_firebase, 10000);
    while (true) { // evig slinga
        std::cout << "Checking if radio is available..." << std::endl;
        if (radio.available()) {
            int payload_size = radio.getDynamicPayloadSize();
            if (payload_size > 1) {
                char* payload = new char[payload_size + 1];
                radio.read(payload, payload_size);
                payload[payload_size] = '\0';
                std::cout << "Got Message: " << payload << std::endl;
                if (curl) {

                    std::string temp = notification();
                    char temp2[temp.length()];
                    strcpy(temp2, temp.c_str());

                    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, temp.c_str());
                    res = curl_easy_perform(curl);
                    /* Check for errors */
                    if (res != CURLE_OK) {
                        fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
                    }
                }
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(5000)); // Vilar programmet 5 sekunder
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
    curl_easy_cleanup(curl2);
    curl_easy_cleanup(curl3);
    curl_global_cleanup();
}

Kod: Markera allt

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include "printf.h"
#include <avr/sleep.h>

int plingPin = 2;
int irqPin = 3;
int relayPin = 8;
int plingStatus = HIGH;
RF24 radio(9, 10); // CE, CSN
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
const char text[] = "PlingPlong!";

volatile bool plingSet = false;
volatile bool rxSet = false;

// Interrupt handler function - Tryck på ringklocka
void pling() {
  sleep_disable();
  detachInterrupt(digitalPinToInterrupt(plingPin));
  detachInterrupt(digitalPinToInterrupt(irqPin));
  plingSet = true;
}

// Interrupt handler function - Inkommande sändning
void rx() {
  sleep_disable();
  detachInterrupt(digitalPinToInterrupt(irqPin));
  detachInterrupt(digitalPinToInterrupt(plingPin));
  rxSet = true;
}

void setup() {
  pinMode(plingPin, INPUT_PULLUP);
  pinMode(irqPin, INPUT_PULLUP);
  pinMode(relayPin, OUTPUT);
  Serial.begin(9600);
  // Arduino lyssnar på pipe 00001 och skriver på pipe 00002
  radio.begin();
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1, pipes[1]);
  radio.setPALevel(RF24_PA_HIGH);
  radio.setChannel(108);
  //radio.setChannel(1);
  radio.maskIRQ(1, 1, 0);
  radio.startListening();
}

void sleepMode() {
  Serial.println("DEBUG: In sleepMode-routine");
  delay(500);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  noInterrupts ();          // make sure we don't get interrupted before we sleep
  sleep_enable();
  attachInterrupt(digitalPinToInterrupt(plingPin), pling, LOW);
  attachInterrupt(digitalPinToInterrupt(irqPin), rx, LOW);
  interrupts ();           // interrupts allowed now, next instruction WILL be executed
  sleep_cpu();
  Serial.println("DEBUG: Waking up from interrupt");

}

void loop() {
  // Någon har plingat på klockan
  if (plingSet) {
    radio.stopListening(); // Stoppa lyssning tillfälligt
    radio.setPALevel(RF24_PA_HIGH);
    Serial.println("DEBUG: Trying to send");
    if (radio.write(&text, sizeof(text))) {
      Serial.println("DEBUG: Send ok");
    } else {
      Serial.println("DEBUG: Send failed");
    }
    radio.startListening(); // Starta lyssning efter att meddelandet är skickat
    delay(5000); // Låt det gå minst 5 sek innan vi skickar en ny pling
    plingSet = false;
  }

  // RPi vill plinga på klockan
  if (rxSet) {
    if ( radio.available()) {
      Serial.println("Radio available");
      int payload_size = radio.getDynamicPayloadSize();
      if (payload_size > 1) {
        // Variable for the received timestamp
        char* payload = new char[payload_size + 1];
        radio.read(payload, payload_size);
        Serial.print("Got this: ");
        Serial.println(payload);
        if (strcmp(payload, "pling") == 0) {
          Serial.println("Driving relay on/off, on/off");
          digitalWrite(relayPin, HIGH);
          delay(500);
          digitalWrite(relayPin, LOW);
          delay(500);
          digitalWrite(relayPin, HIGH);
          delay(500);
          digitalWrite(relayPin, LOW);
          delay(500);
        } else {
          Serial.println("Payload != \"pling\"");
        }
      }
    }
    rxSet = false;
  }

  digitalWrite(relayPin, LOW);
  delay(1000);
  sleepMode();
}

Kod: Markera allt

package com.example.doorbell;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.firebase.ui.auth.AuthUI;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.InstanceIdResult;

import java.util.Arrays;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    TextView statusBox;
    FirebaseDatabase database;
    DatabaseReference myRef;

    private int RC_SIGN_IN;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        database = FirebaseDatabase.getInstance();


        FirebaseInstanceId.getInstance().getInstanceId()
                .addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
                    @Override
                    public void onComplete(@NonNull Task<InstanceIdResult> task) {
                        if (!task.isSuccessful()) {
                            Log.w("tkn", "getInstanceId failed", task.getException());
                            return;
                        }

                        // Get new Instance ID token
                        String token = task.getResult().getToken();

                        DatabaseReference tkn = database.getReference("token");
                        tkn.setValue(token);

                        // Log and toast
                        String msg = getString(R.string.msg_token_fmt, token);
                        Log.d("tkn", msg);
                        //Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
                    }
                });

        View loginButton = findViewById(R.id.button3);
        if (FirebaseAuth.getInstance().getCurrentUser() == null) {
            loginButton.setEnabled(true);
        } else {
            loginButton.setEnabled(false);
        }


        // Write a message to the database
        myRef = database.getReference("ring/status");
        statusBox = findViewById(R.id.textView2);

        myRef.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                String test = dataSnapshot.getValue(String.class);
                statusBox.setText(test);
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }

    public void activate(View v) {
        myRef.setValue("TRUE");
    }

    public void login(View v) {
        // Choose authentication providers
        List<AuthUI.IdpConfig> providers = Arrays.asList(
                new AuthUI.IdpConfig.EmailBuilder().build(),
                new AuthUI.IdpConfig.GoogleBuilder().build());

        // Create and launch sign-in intent
        startActivityForResult(
                AuthUI.getInstance()
                        .createSignInIntentBuilder()
                        .setAvailableProviders(providers)
                        .build(),
                RC_SIGN_IN);
    }


}
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Användarvisningsbild
NULL
Inlägg: 2522
Blev medlem: 15 september 2010, 12:59:25
Ort: Örebro

Re: Arduino-övervakad ringklocka: Lödning experimentkort!

Inlägg av NULL »

Skriv gärna vad ni tycker om mina lödningar, hur kan jag göra det bättre?
De ser OK ut, det blir inte bättre på prototypkort, men vad spelar det för roll när det är just en prototyp? :D
Lödningar blir bra när man har lödmasker och rätt mängd tenn, då fixar ytspänningen så det blir snygga "kurvor" runt allt som tennet suger sig fast mot.
Nille86
Inlägg: 65
Blev medlem: 13 april 2019, 13:10:49

Re: Arduino-övervakad ringklocka: Lödning experimentkort!

Inlägg av Nille86 »

Hallå forumet!

Här kommer en avslutande uppdatering på mitt ringklockeprojekt. Efter att prototypen varit i drift ett tag ritade jag färdigt mitt kretskort i kicad och beställde tre exemplar från OSHpark. Anledningen till att jag valde Oshpark var för att det var så otroligt smidigt att bara ladda upp kicad-filerna direkt utan att behöva lära mig hur jag konverterar till gerber-formatet.

Efter en lång väntan kom korten äntligen och jag satte igång att löda direkt. Jag upptäckte ganska snabbt att jag hade valt fel footprint till min likriktar-IC, hålen satt för tätt för att få i ic'n!
När jag ritade kretskortet var jag noggrann med att kontrollera att min nrf24l01-modul skulle få plats på kortet utan att krocka med kondensatorn. Tyvärr har jag nog råkat spegelvända någonting för den tog såklart emot kondensatorn.

Nåväl, jag "löste" det första problemet genom att böja benen på ic'n och tvingade ner den i hålen på kretskortet och jag löste det andra problemet genom att löda kopplingstråd mellan modulen och kretskortet. Samtidigt valde jag att gå ifrån nrf24l01 och använda en LoRa-modul istället.

På mjukvarusidan så har jag efter mycket jobb lyckats få igång en LoRa-mottagare på min Raspberry Pi med python som programspråk. Fördelen med att använda python är att jag kan använda googles egna bibliotek för firebase och nu har jag en konstant uppkopplad stream till min databas som skickar ett event ifall någonting ändras. Det är dessutom smidigare att skicka notifieringar till telefonen med hjälp av samma bibliotek.

Mjukvaran verkar fungera klockrent, jag får en notifikation från min mobil när någon ringer på ringklockan och jag kan från min mobil göra så att ringklockan ringer.

Jag har garanterat gjort mängder med nybörjarmisstag, framförallt i designen på kretskortet, men istället för att putsa mer på ringklockan går jag vidare till nästa projekt med allt nytt jag lärt mig. Jag har köpt boken "art of electronics" för att lära mig mer på kompontnivå och kretsdesign. Jag tar gärna emot tips på bra böcker som handlar om design av kretskort.

Framtida planer är att köpa ett oscilloskop för att kunna utföra lite nogrannare mätningar på en batterimatad LoRa-nod som jag håller på att bygga. Även en qlocktwo-kopia finns i planerna.

Om någon är intresserad av programkod får ni säga till, det är som sagt gjort i python.
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Skriv svar