Want to build Django Channels Webserver (SQLite) with real time updates from multiple raspberry pi’s (Message on signal change) over a websocket connection.
Therefore i tried to build a simple python script running on the raspberry pi, opening a websocket connection to the Webserver and sending a value update over websocket immediately when a value changes, and only the value changed.
Each value update ought to be stored into the Django database.
A client should be able to access via simple browser application (JavaScript/HTML/CSS) the database and filter it for criteria (like location, battery state, etc.). The visualised data ought to be in real-time, therefore maybe keeping updated directly via channels from the raspberry pi updates.
I ruled out MQTT, since there seems not to be a propper integration into Django.
I wanted to avoid REST API, since it does not provide real real-time behaviour (allthough i could of course send updates every some seconds).
My Proof-of-Concept attempts have been conducted locally on one machine, but i failed already in connecting to the django channels server via python websockets script.
django project name: solserver
django appname: database
websocket-client:
import asyncio
import websockets
class Base():
    """Basic class, containing common functionality among all versions for Raspberry Pi."""
    def __init__(self, serial_number: str, software: str, country: str, postcode: str) -> None:
        self.serial_number = serial_number
        self.software = software # software version
        self.country = country # country
        self.postcode = postcode # postcode
        self.battery = 0 # % - state of charge of the battery
        self.server_url = 'ws://localhost:8000/update/'
        self.publish = True
   
    async def publish_state(self, interval: int = 2):
        """Coro: Periodically publishes instance state to websocket URL."""
        async with websockets.connect(self.server_url) as ws:
            print(f'connected to {self.server_url}')
            while self.publish:
                await ws.send('hello')
                # response = await ws.recv()
                # print(f'response: {response}')
                await asyncio.sleep(interval)
async def main():
    rpi = Base("1234","1.0","at","1040")
    await rpi.publish_state()
    
if __name__ == "__main__":
    print(f'running {__file__}')
    asyncio.run(main())
consumers.py
from channels.generic.websocket import AsyncWebsocketConsumer
class ServerConsumer(AsyncWebsocketConsumer):
    groups = ["broadcast"]
    async def connect(self):
        await self.accept()
routing.py
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
    re_path("update/", consumers.ServerConsumer.as_asgi()),
]
asgi.py
import os
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from django.core.asgi import get_asgi_application
from database.routing import websocket_urlpatterns
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'solserver.settings')
# Initialize Django ASGI application early to ensure the AppRegistry
# is populated before importing code that may import ORM models.
django_asgi_app = get_asgi_application()
application = ProtocolTypeRouter(
    {
        "http": django_asgi_app,
        "websocket": AllowedHostsOriginValidator(
            AuthMiddlewareStack(URLRouter(websocket_urlpatterns))
        ),
    }
)
settings.py
...
INSTALLED_APPS = [
    'daphne',
    'database',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
...
Django Channels Server log:
python .\manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
March 07, 2024 - 16:28:19
Django version 5.0.3, using settings 'solserver.settings'
Starting ASGI/Daphne version 4.1.0 development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
WebSocket HANDSHAKING /update/ [127.0.0.1:55755]
WebSocket REJECT /update/ [127.0.0.1:55755]
WebSocket DISCONNECT /update/ [127.0.0.1:55755]
websocket-client log: (ignore the slightly different file naming on my computer)
running v2.py
Traceback (most recent call last):
  File "v2.py", line 42, in <module>
    asyncio.run(main())
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\lib\asyncio\runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\lib\asyncio\base_events.py", line 649, in run_until_complete
    return future.result()
  File "v2.py", line 41, in main
    await v2.publish_state()
  File "base.py", line 39, in publish_state
    async with websockets.connect(self.server_url) as ws:
  File "client.py", line 629, in __aenter__
    return await self
  File "client.py", line 647, in __await_impl_timeout__
    return await self.__await_impl__()
  File "client.py", line 654, in __await_impl__       
    await protocol.handshake(
  File "client.py", line 325, in handshake
    raise InvalidStatusCode(status_code, response_headers)
websockets.exceptions.InvalidStatusCode: server rejected WebSocket connection: HTTP 403
Utilizing:
Python 3.10.11
Django 5.0.3
Channels 4.0
Docker version 25.0.3
(for Redis Image)
Daphne 4.1.0
Thanks for your thoughts in advance!