smartphone UI for data logging IoT device

We are working on a RPi4 device (with USB camera, Adafruit GPS Hat, PiJuice battery) that logs GPS and collects video (like a dashcam but the video recording is triggered by various events). We’ve got a multicontainer install with balena starter interface, wifi-connect, and our data logger in “bridge” mode on port 8080. Most of the data logging occurs out of wifi/cellular range and the users need a way to ensure the camera is aimed correctly and get a little feedback on the operation of the device while in the field, so we need the captive portal to show a live feed of the camera from the user’s smartphone or tablet (android or ios).
Problem1: I have a flask based UI on the data logger (https) that can display the camera feed, but I can’t figure out the best way to also display that camera feed on the captive page, and the SystemInfo page (when back in wifi range). The Vue webserver is https and it won’t display http content without some complaining about insecure content. This is the @app.route(‘/video_viewer’):

def video_stream():
while True: #get camera frames for display in web UI
frame = video_camera_thread.get_frame()
if frame != None:
yield (b’–frame\r\n’
b’Content-Type: image/jpeg\r\n\r\n’ + frame + b’\r\n\r\n’)

def video_viewer():
return Response(video_stream(), mimetype=‘multipart/x-mixed-replace; boundary=frame’)

Tried inserting this into SystemDeviceInfo.vue:

Problem 2: The captive portal is easy enough for the field user to connect to and display, but when back in wifi range we are uploading all the data collected (to azure IoT Hub) and we want to display some details about the upload progress, and battery charging. I don’t want the user to have to figure out the local IP address for the device on the wifi network. I’ve tried to set the Hostname, but I can’t get the hostname.local URL to bring up the UI from the user’s smartphone (also connected to wifi).

I’m hoping the big brains here have some experience that could speed up my solution process! This is our first balena project. Your help would be much appreciated! Suggestions?

1 Like

It is a little difficult to disaggregate the questions.

It sounds like you have found the CaptivePortal page where you can modify the content: starter-interface/CaptivePortal.vue at main · balena-labs-research/starter-interface · GitHub. That is assuming you are using the included Python-WiFi-Connect shown in the starter interface repo rather than the balena Wifi-Connect.

There isn’t anything displayed where you mentioned what you had tried inserting into SystemDeviceInfo.

I’ve tried to set the Hostname, but I can’t get the hostname.local URL to bring up the UI from the user’s smartphone (also connected to wifi).

Assuming it is running on port 80 and the hostname is accurate, there isn’t any reason that shouldn’t resolve: starter-interface/docker-compose.yml at ac5b15b729295326f97442d659232752cf3de00b · balena-labs-research/starter-interface · GitHub

Out of interest, could you also tell us a bit more about your project and use case?

maggie0002, thanks for your reply. Sorry, I’ve lumped 2 problems into one post. Problem #1 first.
Looks like I forgot to paste in the code I tried in SystemDeviceInfo:

<div class="justify-between row q-mb-sm no-wrap">
  <div class="col"><p><img id="video" src="https://{{ hostname }}:8080/video_viewer"></p></div>

I also tried ip address although that wouldn’t be a sustainable solution with dhcp assigned ip’s.

The device is going on small boats to video activity. Like a dashcam, but the video turns on based on user-defined triggers. Most of their activity time is spent without internet connection. When an internet connection returns it automatically uploads all the logged data/video.

1 Like

Hello @msudul first of all welcome to the balena community! Such an interesting project you are buidling!

This remains me to this birdwatcher project → GitHub - just4give/birdwatcher

Let us know if this helps you to get specific ideas on how to stream the video and upload data/video.

Thx @mpous. I see the birdwatcher project used balenablocks/hostname to try and solve my Problem #2. I’ll try GitHub - maggie0002/balena-tiny-hostname: Set the hostname on Balena devices.

Update: the hostname is set successfully, but it is not resolved on the local wifi network from an iphone for instance. Is there some more dns magic needed?

Update: balena-tiny-hostname worked and multiple devices on the same subnet appear to autorename to hostname-n.local which is great! Problem 2 solved. I abandoned the starter-interface because of problem 1. I might revisit that later.

{{ hostname }} should be {{ hostname}}.local for resolution on local networks. Alternatively you could read whatever is used in the browser when the user is viewing your page to construct the path which would guarantee the same method, being sure to append your port number on the end: window.location Cheatsheet. Learn how to change the URL properties… | by Samantha Ming | DailyJS | Medium. I suspect https isn’t enabled on your video stream either? So would be http rather than https. Https would benefit from a key server that requires internet access.

If you’re using some ssl certs for the front end, it’s most likely better to do it through something like Nginx rather than Flask which isn’t designed for being the only front of a service. If you had Nginx you could then also put starter interface and the Flask app behind it through a reverse proxy, and then both would share the same SSL cert.

In terms of the hostname, both starter interface and that block use the same methods of changing the hostname so can’t see why both shouldn’t work. On starter interface though, after first boot a PID file is created to stop it running again. If you are on a development device, it may have created that pid file and now when you try and deploy the code again it is not triggering the hostname rename. SSH in to device and type ‘hostname’ to get the current hostname. Assuming it’s displayed correctly there then it would be a network issue, maybe a device restart will be required. Or the same devices on the same network issue, which would be the network appending the -n rather than the device. In this case the window.location option would be safer.

Apologies for the delayed response, for some reason I wasn’t getting email notifications on this thread, but enabled now.

@maggie0002, thanks for the detailed response. I’ll circle back and try your suggestions!

OK. I’m trying the correct URL, but the syntax I’m using to build the URL is not working. {{ hostname }} is inside a quoted string, so the hostname doesn’t get replaced. I’m a newb with the Vue.js stuff!

You could look to construct it like this:

<img id="video" :src="`http://${urlHostname}:9000/logo_colour.svg`" />


const urlHostname = window.location.hostname


    return {