1

I am building a DIY sonar using a Raspberry Pi, an ultrasonic sensor and a servo motor and so far I've managed to make it generate a picture/map on each 180 degree sweep but the problem is that I also want to show this picture on a local webpage and I want to make it auto-update on each sweep without the user having to manually refresh the page (each sweep does not last the exact same as the previous one - that is one problem). I have thought of using the BottlePy micro web framework as well as some jSON. Here is the code:

Python:

import pigpio
import time
import RPi.GPIO as GPIO
import numpy as np
import cv2
import math
from PIL import Image as im

import bottle
from bottle import route, run, template, BaseTemplate, static_file

app = bottle.default_app()
BaseTemplate.defaults['get_url'] = app.get_url

@route('/')
def index():
    return template('index.html')


@route('/<filename:path>', name='static')
def serve_static(filename):
    return static_file(filename, root='static')

@route('/refresh')

def refresh():

...
    #matrix generation for map - newmapp
...

    data=im.fromarray(newmapp)
    data.save('/home/pi/Desktop/servo_web/static/map.png')
    
run(host='localhost', port=8080)

HTML/JS:

<!DOCTYPE html>
<html>
<head>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <title>HARTA</title>
</head>
<body>
    <img src="{{ get_url('static', filename='map.png') }}" />
    <script>
      $(document).ready(function(){
        setInterval(refreshFunction,300);
      });

      function refreshFunction(){
        $.getJSON('/refresh', function(){
        });
      }
    </script>
</body>
</html>

Thanks in advance!

davidism
  • 121,510
  • 29
  • 395
  • 339
Theodor
  • 31
  • 4
  • if you use JavaScript to change url to image then browser will reload image. You can add random parameter to url like `map.png?random_value`. Some systems use current time to reload `image` or `css` file - like `map.png?2021.08.17.20.49.43` (`year.month.day.hour.minut.second`) – furas Aug 17 '21 at 18:45

3 Answers3

1

From this question: Refresh image with a new one at the same url, you can try adding a catchbreaker, essentially forcing the browser to reload the image instead of taking it from the cache.

document.querySelector("img").src = `{{ get_url('static', filename='map.png?${new Date().getTime()}') }}`;
Sidarth Nuthi
  • 316
  • 2
  • 7
1

"I want to make it auto-update on each sweep without the user having to manually refresh the page"

Rather than refreshing the page every time, a more complex but efficient option would be to dynamically render the image in the browser using an AJAX GET request. Use setInterval() to send the request repeatedly from the client. The time interval you choose will determine how many requests you will get to the server, smaller interval = more requests. This pattern is known as polling.

Because the browser will try to cache the image rather than updating it, add a cache busting url fragment in the client and cache-control headers to the server response: https://stackoverflow.com/a/9943419/14082992

Bottle can ignore the added URL fragment using a wildcard path to the image: https://bottlepy.org/docs/dev/routing.html#wildcard-filters

Use Bottle's response.set_header to set the cache control headers: https://bottlepy.org/docs/dev/tutorial.html#the-response-object

0

If you add random parameter to url - map.png?random_value (ie. current date with time and seconds) - then browser automatically reload image.

So in JavaScript you can do

<img id="map" src="{{ get_url('static', filename='map.png') }}" />

$.get('/refresh', function(){            
     d = new Date();
     $("#map").attr("src", "{{ get_url('static', filename='map.png') }}?"+d.getTime());            
});  

Minimal working code

import os
import time

import bottle
from bottle import route, run, template, BaseTemplate, static_file

import numpy as np
from PIL import Image

app = bottle.default_app()
BaseTemplate.defaults['get_url'] = app.get_url

@route('/')
def index():
    return template('''<!DOCTYPE html>
<html>
<head>
    <title>HARTA</title>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>
<body>
    <img id="map" src="{{ get_url('static', filename='map.png') }}" />
    <script>
      $(document).ready(function(){
        setInterval(refreshFunction, 1000);
      });

      function refreshFunction(){
        $.get('/refresh', function(){            
            d = new Date();
            $("#map").attr("src", "{{ get_url('static', filename='map.png') }}?"+d.getTime());            
            console.log($("#map").attr("src"));
        });
      }
    </script>
</body>
</html>''')

@route('/<filename:path>', name='static')
def serve_static(filename):
    return static_file(filename, root='static')

@route('/refresh')
def refresh():
    os.makedirs('static', exist_ok=True)
    newmapp = np.random.rand(100,100,3) * 255    
    data = Image.fromarray(newmapp.astype('uint8')).convert('RGBA')
    data.save('static/map.png')
    return "OK" 
    
run(host='localhost', port=8080)
furas
  • 134,197
  • 12
  • 106
  • 148