
Wykrywacz ruchu ze zdjęciami i notyfikacjami
Wstęp
Założenia projektu są dość oczywiste – po wykryciu ruchu zostanie zrobione zdjęcie i wysłana notyfikacja ze zdjęciem na smartfona. Historie zdjęć można podglądać, a dostęp jest nie tylko z sieci lokalnej ale z dowolnego miejsca gdzie tylko jest internet. Zdjęcia można też wykonać w dowolnym momencie po wciśnięciu guzika w aplikacji/ na stronie. Sam program na ESP posiada ustawienia które ograniczają liczbę wykonywanych zdjęć po wykryciu ruchu i domyślnie jest to 2min – co można bardzo łatwo zmienić
Zaczynamy
Cały proces został pokazany na filmie:
Całość jest pokazana na filmie i ogranicza się do zarejestrowania w RemoteMe i wyborze szybkiego projektu
Następnie przechodzimy do zakładki build i wpisujemy potrzebne dane jak model naszego ESP32CAM, hasło do sieci wifi itp. W ostatnim kroku zostanie ściągnięty plik zip ze źródłami projektu który należy wgrać do ESP i zostanie stworzona strona WWW, którą możemy wyeksportować jako aplikacje na smartfona.
Szczegółowo proces budowania projektów z “Quick Project” został opisany w przykładzie wykrywania ruchu z notyfikacjami
W przykładzie tym zostało też pokazane jak zainstalować aplikacje na smartfonie – proces jest analogiczny również tutaj i ogranicza się do zeskanowania kodu QR smartfonem i udzieleniem zgód na umieszczenie aplikacji na pulpicie smartfona. Więcej o aplikacjach w : jak działają aplikacje RemoteMe na smartfonie i o notyfikacjach w RemoteMe
Proces wgrywania
Jest to chyba najbardziej skomplikowana część projektu
zostało to opisane już w niezliczonych poradnikach np tutaj więc nie będę tego opisywał,
w moim filmie pokazałem to w 3:23 minucie:
najważniejsze co trzeba pamiętać żeby wysłać kod to:
- Podłączamy GPIO0 do GND
- Przy podłączonym Gpio do GND klikamy przycisk Reset na ESP
- Odłączamy GPIO0 od gnd
- Wgrywamy kod
- Klikamy reset przy odłączonym GPIO0 od GND
Uruchomienie
po wgraniu kodu do ESP pojawi się nowe urządzenie w zakładce RemoteMe z zieloną ikonką podłączenia
oznacza to że urządzenie prawidłowo zarejestrowało i podłączyło się z naszym kontem w RemoteMe
Żeby uruchomić stronę internetową otwieramy belkę Photo display
, klikamy w plik index.html i wybieramy opcje open in new tab
:
po kliknięciu w przycisk Take a photo będziemy na stronie mieli najnowsze zdjęcie:
i historie po kliknięciu w Open History.
Wszystkie zdjęcia trafiają do folderu photos:
najnowsze zdjęcie ma nazwę “photo.jpg” a starsze maja przyrostek z liczbą im starsze zdjęcie tym większa liczba. Po osiągnięciu limitu plików stare zdjęcia będą kasowane, limit możemy sobie łatwo zwiększyć dysponując naszymi punktami w RemoteMe:
Jak to działa
ESP
najważniejszą funkcją jest void takePhoto()
1 2 3 |
digitalWrite(LED_PIN, HIGH);//flash on camera_fb_t* fb = esp_camera_fb_get(); digitalWrite(LED_PIN, LOW);//flash off |
najpierw włączamy diodę led, robimy zdjęcie i diodkę wyłączamy
remoteMe.setFileContent(2, "photos/photo.jpg", fb->len, fb->buf);
a tutaj jest funkcje RemoteMe która do urządzenia o id 2 (nasza strona internetowa) wysyłamy zdjęcie gdzie piszemy nazwę pod jaką ma być zapisane zdjęcie, jego rozmiar i same zdjęcie jako tablice bajtów ( obrazek jest już w formacie jpg ) . RemoteMe zajmie się resztą ( zapisze plik na naszym koncie, odświeży zdjęcie na pogdlądzie)
funkcje takePhoto zostanie wysłana gdy zostanie wykryty ruch:
1 2 3 4 5 |
if (digitalRead(PIR_PIN) && ((lastSend == 0) || (lastSend + repeatingSendTimeoutSeconds * 1000 < millis()))) { takePhoto(); lastSend = millis(); remoteMe.sendPushNotificationMessage(2, "Move appears", "Move", "badge.png", "icon192.png", "photos/photo.jpg"); } |
najpierw sprawdzamy czy jest stan wysoki na pinie do którego jest podłączony detektor ruchu, i srawdzamy kiedy zostało wysłane ostanie zdjęcie – żeby nie wysyłać zbyt często – parametr repeatingSendTimeoutSeconds
określa liczbę sekund jak ma minąć pomiędzy wysłanymi zdjęciami – domyślnie jest to 120 sekund
po wykryciu ruchu wysyłamy też notyfikację
remoteMe.sendPushNotificationMessage(2, "Move appears", "Move", "badge.png", "icon192.png", "photos/photo.jpg");
trafia ona do urządzenia o id 2 (nasza strona itnernetowa) z tytułem Move appears, obrazak w notyfikacji to nasze zdjęcie dzięki czemu notyfikacja wygląda tak:
Zdjęcie zostanie również zrobione gdy użytkownik kliknie przycisk na stronie, kod wygląda tak:
1 2 3 4 |
void onUserMessage(uint16_t senderDeviceId, uint16_t dataSize, uint8_t* data) { takePhoto(); } |
czyli jak zostanie odebrana wiadomość ( treść jest nieistotna dlatego nie sprawdzam parametrów) zdjęcie zostanie zrobione
Strona WWW/aplikacja
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<div style="width:800px;max-width:calc(100vw - 12px);margin:5px;"> <divstyle="width:100%; position:relative"> <divid="progress"class="mdl-progress mdl-js-progress mdl-progress__indeterminate" style="width:calc(100% - 56px);margin-left:22px;position:absolute;top:30px;border:3px solid white;height: 10px;display:none"></div> <imgid="imageForPhoto"style='width:100%;height: auto;border:1px solid gray;max-height:calc(100vh - 50px)'/> </div> <buttonclass="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--raised"onclick="takePhotoNow()"style="width:100%">Take a photo</button> <buttonclass="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--raised"onclick="location.href='history.html'"style="width:100%;margin-top:20px">Open History</button> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
var cameraDeviceId=1; function takePhotoNow(){ RemoteMe.getInstance().sendUserMessage(cameraDeviceId ,[1]); $("#progress").css("display","block"); } $(document).ready(function () { let remoteme=RemoteMe.getInstance();//connect to RemoteMe and keeps conenction live let fileName = "photos/photo.jpg"; let deviceId = thisDeviceId; let image = $('#imageForPhoto'); image[0].src=`/wp/device_${deviceId}/${fileName}?r=${Math.floor(Math.random() * 10000)}`; image[0].onload = function() { $("#progress").css("display","none"); }; remoteme.remoteMeConfig.deviceFileChange.push((rdeviceId,rfileName)=>{ if ((deviceId==rdeviceId)&&(rfileName==fileName)){ image[0].src=`/wp/device_${deviceId}/${fileName}?r=${Math.floor(Math.random() * 10000)}`; } }); remoteme.subscribeEvent(EventSubscriberTypeEnum.FILE_CHANGE); }); |
var cameraDeviceId=1;
nasze urządzenie ESP na id 1 i do tego urządzenie wysyłamy wiadomość gdy chcemy żeby zrobiło zdjęcie:
function takePhotoNow(){
RemoteMe.getInstance().sendUserMessage(cameraDeviceId ,[1]);
$("#progress").css("display","block");
}
image[0].onload = function() {
$("#progress").css("display","none");
};
remoteme.remoteMeConfig.deviceFileChange.push((rdeviceId,rfileName)=>{
if ((deviceId==rdeviceId)&&(rfileName==fileName)){
image[0].src=/wp/device_${deviceId}/${fileName}?r=${Math.floor(Math.random() * 10000)}
;
}
});
rfileName==fileName
(nie chcemy odświeżać zdjęcia gdy np zmodyfikujemy plik index.html)) i zmieniony został na na naszym urządzeniu (deviceId==rdeviceId)
r
jest losowy i zmusza przeglądarkę do załadowania zdjęcia z serwera, a nie z lokalnego bufora)Historia zdjęć:
<gallery imageWidth="450px" imageHeight="75vw" mask="photos/photo(_\d+)?.jpg" style="margin-top:20px" displayDate="true" dateFormat="DD.MM.YYYY HH:mm" ></gallery>
remotemecomponents.js
) w funkcji function addGallery(selector)
Podsumowanie
zachęcam do bawienia się kodem – dopisywanie swoich funkcjonalności 🙂