{"id":23925530,"url":"https://github.com/mhwlng/kiosk-server","last_synced_at":"2025-04-12T03:41:33.796Z","repository":{"id":60132763,"uuid":"541054787","full_name":"mhwlng/kiosk-server","owner":"mhwlng","description":"touch screen kiosk with multi-platform remote control web server using blazor and net9","archived":false,"fork":false,"pushed_at":"2025-03-07T18:42:59.000Z","size":150,"stargazers_count":28,"open_issues_count":0,"forks_count":6,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-25T23:14:48.116Z","etag":null,"topics":["blazor-server","compute-module-4","compute-module-5","home-assistant","kiosk","kiosk-software","mudblazor","multi-platform","net9","raspberry-pi","raspberrypi","touchscreen"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mhwlng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-25T04:52:40.000Z","updated_at":"2025-03-07T18:43:03.000Z","dependencies_parsed_at":"2023-11-19T10:24:50.975Z","dependency_job_id":"e0bf0479-df92-4cb5-b267-77292a82c8cb","html_url":"https://github.com/mhwlng/kiosk-server","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhwlng%2Fkiosk-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhwlng%2Fkiosk-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhwlng%2Fkiosk-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhwlng%2Fkiosk-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mhwlng","download_url":"https://codeload.github.com/mhwlng/kiosk-server/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248514221,"owners_count":21116899,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blazor-server","compute-module-4","compute-module-5","home-assistant","kiosk","kiosk-software","mudblazor","multi-platform","net9","raspberry-pi","raspberrypi","touchscreen"],"created_at":"2025-01-05T20:14:39.849Z","updated_at":"2025-04-12T03:41:33.789Z","avatar_url":"https://github.com/mhwlng.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kiosk-server\n\nTouch screen kiosk with multi-platform remote control web server, using blazor and net9.\n\nDisplay when no Kiosk URL is defined yet:\n\n![touch screen](https://i.imgur.com/bTQtqSe.png)\n\nWhen using the external setup URL (http://x.x.x.x:5000/setup, no password authentication) you can enter one or more Kiosk URLs and then either reboot or shutdown the raspberry pi.\n\nThe Kiosk URL is only shown after a reboot.\n\nIf there is only one Kiosk URL, then the software will redirect to that URL at startup.\n\nIf there is more than one Kiosk URL defined, then the software will redirect to an internal page (http://x.x.x.x:5000/kiosk) that has a tab bar at the top and an iframe filling the rest of the screen. \n\nThe contents of the iframe is changed to the Kiosk URL, after pressing the tab button with the name of the Kiosk URL.\n\nIf you see a blank iframe with an error like 'www.msn.com refused to connect.' :\nThat means that the remote web server does not allow rendering inside an iframe. (via the X-Frame-Options http response header)\n\nYou won't have this problem, if you define just one Kiosk URL.\n\nThere is also a page http://x.x.x.x:5000/blank that shows a blank page.\n\nThere is also a (GET) rest api endpoint (http://x.x.x.x:5000/api/status) that returns a JSON object, containing system status data.\n\nThere are also (POST) rest api endpoints (http://x.x.x.x:5000/api/shutdown , http://x.x.x.x:5000/api/reboot , http://x.x.x.x:5000/api/screenoff and http://x.x.x.x:5000/api/screenon) NOTE that there is no authentication!\n\nAlso, a (POST) rest api endpoint has been added (http://x.x.x.x:5000/api/stopchromium) , that kills the chromium process.\n\nThere is also a (POST) rest api endpoint http://x.x.x.x:5000/api/navigatetourl?url=xxxxxxx that ONLY works, when the kiosk screen is being displayed.\n\nWhen this url is POSTed, with ANY url as query parameter (e.g. http://x.x.x.x:5000/api/navigatetourl?url=http://x.x.x.x:5000/blank) that page will be loaded into the kiosk iframe and the tab bar at the top is hidden.\n\nWhen this url is POSTed, without any url as query parameter (e.g. http://x.x.x.x:5000/api/navigatetourl?url=) then the kiosk is reloaded and the tab bar at the top reappears.\n\n![touch screen](https://i.imgur.com/Wzp5kqm.png)\n\n![touch screen](https://i.imgur.com/cXrHx23.png)\n\n## Test Environment\n\n**This software works with any kind of display. I have been testing with ultra-wide displays :**\n\n3D-printed enclosures, for these displays, can be found : https://www.printables.com/@mhwlng_888536/collections/920676\n\nTouch Display 1920x480 (8.8 inch, IPS panel, default orientation is portrait):\n\nhttps://www.aliexpress.com/item/1005003014364673.html\n\n![touch screen](https://i.imgur.com/QWs2S9S.jpg)\n\n![touch screen](https://i.imgur.com/GfcSTTd.jpg)\n\nThe 3 Dials have an ESP32 processor and are made by M5Stack :\n\nhttps://shop.m5stack.com/products/m5stack-dial-esp32-s3-smart-rotary-knob-w-1-28-round-touch-screen\n\n![touch screen](https://i.imgur.com/0NSFRaz.jpg)\n\nTouch Display 1920x515 (12.6 inch, IPS panel):\n\nhttps://www.aliexpress.com/item/1005001966967133.html\n\n[3d printed modular dashboard](https://www.printables.com/@mhwlng_888536/collections/920676)\n\n![touch screen](https://i.imgur.com/hFIeCUD.jpg)\n\n![touch screen](https://i.imgur.com/4YI13mJ.jpg)\n\n![touch screen](https://i.imgur.com/erLvZY7.jpg)\n\nTouch display 3840x1100 (14 inch, IPS panel, uses usb-c connector for power and touch screen):\n\nhttps://www.aliexpress.com/item/1005003332731770.html\n\n[3d printed modular dashboard](https://www.printables.com/@mhwlng_888536/collections/920676)\n\n![touch screen](https://i.imgur.com/MjmCNvf.jpg)\n\n![touch screen](https://i.imgur.com/ysxHEvS.jpg)\n\nRaspberry Pi Compute Module 4 (I only have the 8GB RAM / 16GB EMMC version)\n\nThe Waveshare CM4-NANO-B expansion board (also available on Amazon)\n\nhttps://www.waveshare.com/wiki/CM4-NANO-B\n\nThe USB-C port is connected to the 5V power. (Also used to put the OS image onto the EMMC flash.)\n\nThe USB-A port is connected to the display. (To power it and also for the touch screen)\n\nThe HDMI port is connected to the display HDMI port.\n\nPressing the pushbutton (GPIO21) shuts down the CM4\n\n# Installation Instructions\n\nI mainly used this document as a guideline: (note that for the CM4 it's not exactly the same)\n\nhttps://gist.github.com/fjctp/210f4e870f913416b8d0e17fd36153c2\n\n\n## Install bootloader on CM4\n\nhttps://www.raspberrypi.com/documentation/computers/compute-module.html\n\nSet boot switch to on, plug in usb-c \n\nDownload rpiboot_setup.exe, run rpiboot.exe \n\nAlso see waveshare CM4-NANO-B wiki page.\n\nhttps://github.com/raspberrypi/usbboot/raw/master/win32/rpiboot_setup.exe\n\n- Install raspberry pi os lite 64 bit (bookworm)\n- Set up wifi\n- Set up ssh\n- Set up an account (The instructions and various configuration files assume pi/raspberry Adjust as required.)\n\nAfter connecting via ssh :\n```\nsudo apt-get update\n\nsudo apt-get upgrade\n\nsudo raspi-config\n\nSelect system \\ boot+autologin \\ B2 Console autologin text console\n\nsudo apt-get install -y --no-install-recommends xserver-xorg x11-xserver-utils xinit openbox\n\nsudo apt-get install -y --no-install-recommends chromium-browser\n```\n\n## Edit /boot/firmware/config.txt\n\n**Note: These HDMI resolution configurations do NOT work on Raspberry Pi 5 / CM5 !**\n\nFor Touch Display 1920x480 (portrait orientation, default) :\n```\ndtoverlay=vc4-fkms-v3d # note that this was vc4-kms-v3d before !!!!!\n\nmax_framebuffer_height=1920\nhdmi_timings=480 1 48 32 80 1920 0 3 10 56 0 0 0 60 0 75840000 3\nhdmi_group=2\nhdmi_mode=87\n\n#otg_mode=1\ndtoverlay=dwc2,dr_mode=host\ndtoverlay=gpio-shutdown,gpio_pin=21\n\ngpu_mem=256\n```\n\nFor Touch Display 1920x480 (landscape orientation, rotate 90\u0026deg;) also add:\n```\ndisplay_hdmi_rotate=1\n```\n\nFor landscape orientation: the touchscreen also needs to be rotated 90\u0026deg; :\n\nEdit /usr/share/X11/xorg.conf.d/40-libinput.conf\n\nAdd the TransformationMatrix option to the existing touchscreen InputClass:\n```\nSection \"InputClass\"\n        Identifier \"libinput touchscreen catchall\"\n        MatchIsTouchscreen \"on\"\n        Option \"TransformationMatrix\" \"0 1 0 -1 0 1 0 0 1\"\n        MatchDevicePath \"/dev/input/event*\"\n        Driver \"libinput\"\nEndSection\n```\n\nFor Touch Display 1920x515 :\n```\ndtoverlay=vc4-fkms-v3d # note that this was vc4-kms-v3d before !!!!!\n\nhdmi_group=2\nhdmi_mode=87\nhdmi_cvt=1920 515 60 6 0 0 0\n\n#otg_mode=1\ndtoverlay=dwc2,dr_mode=host\ndtoverlay=gpio-shutdown,gpio_pin=21\n\ngpu_mem=256\n```\n\nFor Touch Display 3840x1100 :\n```\ndtoverlay=vc4-fkms-v3d # note that this was vc4-kms-v3d before !!!!!\n\nhdmi_enable_4kp60=1\nhdmi_group=2\nhdmi_mode=87\nhdmi_cvt=3840 1100 60\n\n#otg_mode=1\ndtoverlay=dwc2,dr_mode=host\ndtoverlay=gpio-shutdown,gpio_pin=21\n\ngpu_mem=256\n```\n\n## Edit /etc/xdg/openbox/autostart\n\n```\nxset s off\nxset s noblank\nxset -dpms\n\nsetxkbmap -option terminate:ctrl_alt_bksp\n\nsed -i 's/\"exited_cleanly\":false/\"exited_cleanly\":true/' ~/.config/chromium/'Local State'\nsed -i 's/\"exited_cleanly\":false/\"exited_cleanly\":true/; s/\"exit_type\":\"[^\"]\\+\"/\"exit_type\":\"Normal\"/' ~/.config/chromium/Default/Preferences\n\n# delete all chromium cached data\nrm -rf ~/.cache/chromium\n\n# delete cookies\n#rm -rf ~/.config/chromium\n\nchromium-browser --noerrdialogs --disable-infobars --kiosk 'http://127.0.0.1:5000'\n```\n\nFor the 3840x1100 screen, you can increase the zoom level of chromium using --force-device-scale-factor=1.5 on the command line.\n\nIf the web page checks for the dark mode system setting, --force-dark-mode --enable-features=WebContentsForceDark can be added to the command line.\n\nTo disable the cache mechanism, --disk-cache-dir=/dev/null can be added to the command line.\n\nSome chromium performance related flags can be found here :\n\nhttps://github.com/Botspot/pi-apps/blob/master/apps/Better%20Chromium/install\n\nsome more chromium flags can be found here :\n\nhttps://itnext.io/raspberry-pi-read-only-kiosk-mode-2022-complete-tutorial-df7fc051fdaf\n\n```\nchromium-browser --ignore-gpu-blacklist --enable-checker-imaging --cc-scroll-animation-duration-in-seconds=0.6 --disable-quic --enable-tcp-fast-open --enable-experimental-canvas-features --enable-scroll-prediction --enable-simple-cache-backend --max-tiles-for-interest-area=512 --num-raster-threads=4 --default-tile-height=512 --enable-features=VaapiVideoDecoder,VaapiVideoEncoder --disable-features=UseChromeOSDirectVideoDecoder,TouchpadOverscrollHistoryNavigation --enable-accelerated-video-decode --enable-low-res-tiling --process-per-site --start-fullscreen --disable-translate --no-first-run --fast --fast-start --disable-features=TranslateUI --password-store=basic --disable-pinch --overscroll-history-navigation=disabled --noerrdialogs --disable-infobars --kiosk 'http://127.0.0.1:5000'\n```\n\n## Edit ~/.profile\n\n```\n[[ -z $DISPLAY \u0026\u0026 $XDG_VTNR -eq 1 ]] \u0026\u0026 startx -- -nocursor\n```\n\n## CM5\n\nOn CM5, I could not get custom resolutions to work. So, I use a standard 1920x1080 touch screen.\n\nI installed the full 64-bit Raspberry Pi OS, with auto login into the graphical desktop.\n\nBy default, the combination wayland + labwc is installed.\n\nIn this situation, scrolling the chromium browser with your finger does not work. \n(It acts like a mouse, so you must drag on the scrollbar with your finger, to scroll.)\n\nSo, I switched to the wayland + wayfire combination:\n\n```\nsudo raspi-config \n\nSelect advanced options \\ wayland \\ W2 wayfire\n```\n\nI then created a script file, with the desired command line options, to start the kiosk:\n\n~/run_kiosk.sh\n\n```\nsleep 4\n/bin/chromium-browser --no-first-run --noerrdialogs --disable-infobars --ozone-platform=wayland --start-fullscreen --force-dark-mode http://127.0.0.1:5000 \u0026\n```\n\nNote, that I did not add the --kiosk option. Now, the button, to toggle full screen mode, works. (By simulating the F11 key. This requires the 'wtype' application to be installed.)\n\nWith the --kiosk option, this F11 key is blocked, UNTIL the first screen off/on cycle, when kiosk mode is disabled anyway....\n\nTo install wtype:\n\n```\nuse sudo apt install wtype \n```\n\nThe default desktop installation comes with an on screen keyboard, with a button on the top right, to activate it.\n\nThe keyboard is not activated automatically in chromium. So, this requires 'full screen' mode to be turned off, before being able to press the keyboard button.\n\nI then added to ~/.config/wayfire.ini\n\n```\n[autostart]\nkiosk = ~/run_kiosk.sh\n```\n\nNote, that this wayfire.ini file does not exist, when using the default labwc configuration. \n\n(When Using labwc instead of wayfire, an autostart file must be created here ~/.config/labwc/autostart)\n\n\nHDMI monitor on / off works different for each environment:\n\nUse the screenoff2 / screenon2 rest api functions for labwc\n\nUse the screenoff3 / screenon3 rest api functions for wayfire. This is what I use now.\n\nAfter turning the screen back on, the browser is no longer full screen.\n\nthe screenon3 api function also calls 'wtype' to send the F11 key, to go back to full screen.\n\n\n## Web Server\n\nCopy all the web server application files and subdirectories to ~/kiosk-server\n\nMake application runnable using :\n```\nsudo chmod +x ~/kiosk-server/kiosk-server\n```\n\nInstall the application as a service (Adjust kiosk-server.service if user or directory is different) :\n```\nsudo systemctl stop kiosk-server\n\nsudo cp ~/kiosk-server/kiosk-server.service /etc/systemd/system/kiosk-server.service\n\nsudo systemctl daemon-reload\n\nsudo systemctl enable kiosk-server\n\nsudo systemctl start kiosk-server\n```\n\nCheck if service is running ok :\n```\nsudo systemctl status kiosk-server\n\nor\n\nsudo journalctl -u kiosk-server \n```\n\n## Visual Studio Publish Action\n\nWhen using 'Publish' -\u003e Visual Studio automatically synchronises all files to ~/kiosk-server using WinSCP.\n\nAdjust paths, ip address, user and password in .csproj file as required :\n```\n\u003cTarget Name=\"PiCopy\" AfterTargets=\"AfterPublish\"\u003e\n   \u003cExec Command=\"\u0026quot;C:\\Program Files (x86)\\WinSCP\\WinSCP.com\u0026quot; /command \u0026quot;open sftp://pi:raspberry@192.168.2.36/\u0026quot; \u0026quot;synchronize remote C:\\dotnet\\projects\\kiosk-server\\kiosk-server\\bin\\Release\\net9.0\\publish /home/pi/kiosk-server/\u0026quot; \u0026quot;exit\u0026quot;\" /\u003e\n\u003c/Target\u003e\n```\n\nAlternatively, you could also copy all the files using pscp, that comes with putty:\n\n```\nTarget Name=\"PiCopy\" AfterTargets=\"AfterPublish\"\u003e\n   \u003cExec Command=\"pscp -r -pw raspberry C:\\dotnet\\projects\\kiosk-server\\kiosk-server\\bin\\Release\\net9.0\\publish\\ pi@192.168.2.36:/home/pi/kiosk-server/\" /\u003e\n\u003c/Target\u003e\n```\n\nFirst stop the web server, before updating the files :\n```\nsudo systemctl stop kiosk-server\n```\n\n## Home Assistant Dashboards\n\nhome assistant doesn't work inside an iframe, until you add to the configuration.yaml\n\n```\nhttp:\n  use_x_frame_options : false\n```\n\nThere is no on-screen keyboard, so an auto login mechanism is required:\n\nAdd a new user 'Kiosk'\n\nThe user id can be found on the details pop-up:\n![home assistant](https://i.imgur.com/MzeJlGT.png)\n\nThen, add the IP address of the kiosk as trusted network and the Kiosk user id as a trusted user to configuration.yaml:\n```\n# Allow login without password from local network\nhomeassistant:\n  auth_providers:\n    - type: trusted_networks\n      trusted_networks:\n        - 192.168.2.36/32\n      trusted_users:\n        192.168.2.36:\n          - dacfc03879144b31b57104cc00f6a1a2 ## specific user for kiosk\n      allow_bypass_login: true\n    - type: homeassistant\n```\n\nYou can use the normal home assistant header navigation buttons, to switch between dashboards. \n\nOr you can also add each dashboard URL separately to the Kiosk URL List:\n\n![touch screen](https://i.imgur.com/cXrHx23.png)\n\n![home assistant](https://i.imgur.com/xlLNF75.jpg)\n\nI installed the 'Kiosk Mode' HACS frontend repository. See https://github.com/NemesisRE/kiosk-mode\n\nNow, you can use the kiosk query parameter, to hide the header and sidebar on the dashboard:\n\nFor example : http://192.168.2.73:8123/lovelace/home?kiosk\n\nNote, that this only works correctly, if you hide the sidebar by default, for the Kiosk user:\n\n![home assistant](https://i.imgur.com/pKVELn4.png)\n\n## Transfer system status data to Home Assistant\n\n```\n\nsensor:\n  - platform: rest\n    name: kiosk_sensors\n    scan_interval: 60\n    resource: http://192.168.2.38:5000/api/status\n    json_attributes:\n        - disk\n        - temperature\n        - memory\n        - cpu\n    value_template: \"OK\"\n\n  - platform: template\n    sensors:\n      kiosk_temperature:\n        unique_id: kiosk_temperature\n        friendly_name: \"CPU Temperature\"\n        value_template: \"{{ state_attr('sensor.kiosk_sensors', 'temperature')['cpuTemperature'] | round(1) }}\"\n        device_class: temperature\n        unit_of_measurement: \"°C\"\n      kiosk_cpu_percent:\n        unique_id: kiosk_cpu_percent\n        friendly_name: \"CPU Usage\"\n        value_template: \"{{ state_attr('sensor.kiosk_sensors', 'cpu')['cpuUsage'] | round(1)}}\"\n        unit_of_measurement: \"%\"\n```\n\n\n## Turn off kiosk when PC is turned off\n\n```\n\nrest_command:\n  kiosk_off:\n    url: \"http://192.168.2.38:5000/api/shutdown\"\n    method: POST\n\nbinary_sensor:\n  - platform: ping\n    host: 192.168.2.35\n    name: dev5_ping\n    scan_interval: 60\n  - platform: template\n    sensors:\n      dev5_online:\n        unique_id: dev5_online\n        friendly_name: \"DEV5 Online\"\n        delay_off:\n          minutes: 2\n        value_template: \"{{ states('binary_sensor.dev5_ping')}}\"\n   \nautomation\n   \n- id: '...........'\n  alias: kiosk off when DEV5 off\n  description: ''\n  trigger:\n  - platform: state\n    entity_id:\n    - binary_sensor.dev5_online\n    from: 'on'\n    to: 'off'\n  condition: []\n  action:\n  - service: rest_command.kiosk_off\n    data: {}\n  mode: single\n        \n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmhwlng%2Fkiosk-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmhwlng%2Fkiosk-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmhwlng%2Fkiosk-server/lists"}