Camera Alert app allows viewing of motion image and video information that are captured by security cameras or Ring doorbell.

Security camera needs to have ability to save captured image and video to a FTP drive.

Camera Alert monitors the FTP drive, lists videos and images and sends notifications when new files arrive - created by detected motion.

Currently, I’m using bunch of Reolink RLC-410 cameras, but this should work with any security cameras with FTP support.



Android App

Get on GitHub

Android App

Features

  • Lists recent photo and video files captured by security cameras.
  • Supports FTP storage and Ring doorbell.
  • Allows video playback.
  • Movement notifications

Android push notifications using Google FCM.

Camera Alert using Google FCM to publish notifications from server to the client. Android app needs the Google services keys added as they are not included with the GitHub code.

  1. Go to Firabase, login with your Google account and click on Go to Console.
  2. Click on Add Project and enter the project name.
  3. Click on Create Project to create the project.
  4. Click on Project Settings.
  5. Under General tab, click on Add App and select Add firebase to your Android app.
  6. Give your Android package name and click on Register App button.
  7. Click on download google-services.json.
  8. Include the google-services.json file under the app folder of the Android app.

Firebase related events need to be registered in AndroidManifest.xml.

<service
    android:name=".Services.FirebaseInstanceService">
    <intent-filter>
        <action ndroid:name="com.google.firebase.INSTANCE_ID_EVENT"/>
    </intent-filter>
</service>
<service
    android:name=".Services.FirebaseMessageService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>

INSTANCE_ID_EVENT event handler implemented in FirebaseInstanceService.java and it notifies the server about the token change.

@Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        Log.d(TAG, "Refreshed token: " + refreshedToken);

        sendRegistrationToServer(refreshedToken);
    }

    private void sendRegistrationToServer(String token) {
        RESTMgr service = RESTMgr.getInstance();
        service.setToken(token, null);
    }

MESSAGING_EVENT event handler implemented in FirebaseMessageService.java

@Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        TimeZone utc = TimeZone.getTimeZone("UTC");

        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        f.setTimeZone(utc);

        GregorianCalendar cal = new GregorianCalendar(utc);

        //Log.d(TAG, "From: " + remoteMessage.getFrom());

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0)
        {
            Log.d(TAG, "Message data payload: " + remoteMessage.getData());

            try
            {
                java.util.Map<String, String> map = remoteMessage.getData();

                String eventTime = map.get("date");
                int cameraId = Integer.parseInt(map.get("cameraId"));
                String cameraName = map.get("cameraName");

                cal.setTime(f.parse(eventTime));
                Date eventDate = cal.getTime();

                CreateAlert(String.format("Motion detected at %s", cameraName), cameraId, eventDate);
            }
            catch (ParseException ex)
            {
                Log.d(TAG, "Parse error");
            }
        }

        // Check if message contains a notification payload.
        if (remoteMessage.getNotification() != null) {
            Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
        }
    }

The server part of the FCM will be included in the Node.JS server configuration.

Server Authentication

Following lines in RESTMgr.java need to me modified with the actual username and password:

// need to change to actual values
    private String USERNAME = "admin";
    private String PASSWORD = "admin";