{"id":29223619,"url":"https://github.com/espaciosoa/inmap-pi","last_synced_at":"2026-05-17T15:06:57.969Z","repository":{"id":302432824,"uuid":"1011868533","full_name":"espaciosoa/inmap-pi","owner":"espaciosoa","description":"InMap Companion measurement module for Raspberry Pi","archived":false,"fork":false,"pushed_at":"2025-07-02T10:11:58.000Z","size":47514,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-02T11:26:30.395Z","etag":null,"topics":["5g","inmap","raspberry-pi","signal-measurement"],"latest_commit_sha":null,"homepage":"https://measurements.espaciosoa.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/espaciosoa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null}},"created_at":"2025-07-01T13:05:18.000Z","updated_at":"2025-07-02T10:26:44.000Z","dependencies_parsed_at":"2025-07-02T11:37:07.050Z","dependency_job_id":null,"html_url":"https://github.com/espaciosoa/inmap-pi","commit_stats":null,"previous_names":["espaciosoa/inmap-pi"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/espaciosoa/inmap-pi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/espaciosoa%2Finmap-pi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/espaciosoa%2Finmap-pi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/espaciosoa%2Finmap-pi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/espaciosoa%2Finmap-pi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/espaciosoa","download_url":"https://codeload.github.com/espaciosoa/inmap-pi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/espaciosoa%2Finmap-pi/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263264651,"owners_count":23439257,"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":["5g","inmap","raspberry-pi","signal-measurement"],"created_at":"2025-07-03T05:05:36.305Z","updated_at":"2025-10-17T01:12:30.269Z","avatar_url":"https://github.com/espaciosoa.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\u003cdiv align=\"center\" \u003e\n  \u003ch1\u003e \u003cimg src=\"https://github.com/user-attachments/assets/3dc5878a-aafc-4b55-aa1b-b9d3039faf32\"  width=\"40px\" height=\"40px\" /\u003e InMap-Pi - Indoors Signal Mapper (High precision measurement module for Raspberry Pi)\u003c/h4\u003e\n\u003c/div\u003e\n\n\u003cp align=\"left\"\u003e\n  \u003cimg src=\".showcase/logo.png\" width=\"300\"\u003e\u003cbr\u003e\n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n\u003cimg src=\"https://github.com/user-attachments/assets/df31ad46-1138-4ba1-aac1-85806de89264\"  width=\"50%\"/\u003e \n\u003c/div\u003e\n\n\n\nThe project consists of a node application that communicates via Serial Port with a cell connectivity module (Quectel RM520N-GL) and allows extracting information regarding the cell signal quality through AT commands.\n\nAT commands are wrapped around a very simple (async / promises interface) and results of the different commands are parsed into a JS object representations that aim to make the returned information more human-readable.\n\nThen, the UI provided allows sending the measured data to a Backend server to link the measurements with a given measured Room.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\".showcase/raspi-demo.gif\" width=\"50%\"/\u003e\n\u003c/p\u003e\n\n## Getting started\n\nYou may want to create an .env file if it does not exist already, set at least the following values depending on your SIM and deploying requirements\n\n```sh\nLOCAL_PORT=\"Your local port\" # E.g., 3000 (where the browser page will be available)\nSIM_PIN=1234 # The SIM PIN\nBACKEND_SERVER=\"https://{yourServer}.../v1/API\" # You may need to change the specific urls if the API changes a lot\nFIXED_AUTH_TOKEN=\"YOUR TOKEN\" \n```\n\n- For execution: Run `npm run prod` for running the initialization of the 5G module through a sequence of AT commands and starting the web server locally.\n\n- For development : Run `npm run dev` runs nodemon so that you can preview changes quickly.\n\n\n\n## Triggering Measurements \nThe application exposes a Web server that exposes REST endpoints to request the execution of various AT command sequences and obtain the results as JSON.\n\nA simple web UI page has been created to interact with the Quectel module as a non-programmer user.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\".showcase/ui.png\" width=\"300\" \u003e\n  \u003cimg src=\".showcase/ui-v2.png\" width=\"300\" \u003e\u003c/br\u003e\n  \u003cem\u003eThe GUI to trigger the measurements from the browser\u003c/em\u003e\n\u003c/p\u003e\n\n\n## Sample format of generated measurements\n\n```json\n{\n        \"_id\": \"14b47432-b3a2-4224-99e1-2491562831fb\",\n        \"roomId\": \"447df539-7f8b-470e-90ae-9377d282e12c\",\n        \"timestamp\": \"2025-04-23T08:59:33.868Z\",\n        \"position\": {\n            \"x\": 0,\n            \"y\": 0,\n            \"z\": 0\n        },\n        \"version\": 1,\n        \"measurementOwner\": \"ESOA\",\n        \"measurementDevice\": \"RaspberryPi4B\",\n        \"allMeasurements\": {\n            \"signalStrength\": {\n                \"rssi\": 22,\n                \"rssiMeaning\": \"(-109 dBm to -53 dBm)\",\n                \"channelBitErrorRate\": 99,\n                \"channelBitErrorRateMeaning\": \"Not known or not detectable\"\n            },\n            \"qrsrp\": [\n                {\n                    \"prx\": -108,\n                    \"drx\": -121,\n                    \"rx2\": \"Invalid\",\n                    \"rx3\": \"Invalid\",\n                    \"radioAccessTech\": \"LTE\"\n                },\n                {\n                    \"prx\": -79,\n                    \"drx\": -99,\n                    \"rx2\": -105,\n                    \"rx3\": -109,\n                    \"radioAccessTech\": \"NR5G\"\n                }\n            ],\n            \"qrsrq\": [\n                {\n                    \"prx\": -20,\n                    \"drx\": -18,\n                    \"rx2\": \"Invalid\",\n                    \"rx3\": \"Invalid\",\n                    \"radioAccessTech\": \"LTE\"\n                },\n                {\n                    \"prx\": -10,\n                    \"drx\": -14,\n                    \"rx2\": -11,\n                    \"rx3\": -11,\n                    \"radioAccessTech\": \"NR5G\"\n                }\n            ],\n            \"sinr\": [\n                {\n                    \"prx\": -5,\n                    \"drx\": -3,\n                    \"rx2\": \"Invalid\",\n                    \"rx3\": \"Invalid\",\n                    \"radioAccessTech\": \"LTE\"\n                },\n                {\n                    \"prx\": 22,\n                    \"drx\": 1,\n                    \"rx2\": -1,\n                    \"rx3\": -7,\n                    \"radioAccessTech\": \"NR5G\"\n                }\n            ],\n            \"servingCell\": {\n                \"state\": \"NOCONN\",\n                \"stateExplanation\": \"UE is camping on a cell and has registered on the network and it is in idle mode\",\n                \"mode\": \"EN-DC\",\n                \"cells\": [\n                    {\n                        \"accessTechnology\": \"LTE\",\n                        \"is_tdd\": \"\\\"FDD\\\"\",\n                        \"mcc\": \"214\",\n                        \"mnc\": \"07\",\n                        \"cellId\": \"4472920\",\n                        \"pcid\": \"149\",\n                        \"earfcn\": \"2850\",\n                        \"freq_band_ind\": \"7\",\n                        \"ul_bandwidth\": \"5\",\n                        \"dl_bandwidth\": \"5\",\n                        \"tac\": \"6FC3\",\n                        \"rsrp\": -108,\n                        \"rsrq\": -19,\n                        \"rssi\": \"-67\",\n                        \"sinr\": \"8\",\n                        \"sinr_computed\": -4,\n                        \"cqi\": 8,\n                        \"tx_power\": \"229\",\n                        \"srxlev\": \"-\"\n                    },\n                    {\n                        \"accessTechnology\": \"NR5G-NSA\",\n                        \"mcc\": \"214\",\n                        \"mnc\": \"07\",\n                        \"pcid\": \"434\",\n                        \"rsrp\": -79,\n                        \"sinr\": 22,\n                        \"rsrq\": -10,\n                        \"arfcn\": \"636576\",\n                        \"band\": \"78\",\n                        \"nr_dl_bandwidth\": \"12\",\n                        \"scs\": \"1\"\n                    }\n                ]\n            }\n        },\n        \"measurementSession\": \"UNASSIGNED\"\n    }\n```\n\n## Hardware employed\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\".showcase/raspberry.jpeg\" width=\"300\"\u003e\u003cbr/\u003e\n  \u003cem\u003e\u003cb\u003eRaspberry PI 4B\u003c/b\u003e  with \u003cb\u003eWaveshare 5-inch Capacitive 5-Points Touch Display\u003c/b\u003e \u003c/em\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\".showcase/quectel-RM520N-GL.png\" width=\"300\"\u003e  \u003cbr/\u003e\n  \u003cem\u003e\u003cb\u003eQuectel RM520N-GL\u003c/b\u003e  | Firmware Revision: RM520NGLAAR03A03M4G \u003c/em\u003e\n \u003c/p\u003e\n\n### Reference sheets 🗎\n\nFor installation of the components, I roughly relied on the [Waveshare Wiki (RM520N-GL 5G HAT)](https://www.waveshare.com/wiki/RM520N-GL_5G_HAT#5G_Network_Card_Dial-up_Method), although it is not very thorough. The organization of the page is quite horrible.\n\nSee [RM520N-GL AT Commans Manual](https://files.waveshare.com/upload/8/8a/Quectel_RG520N%26RG52xF%26RG530F%26RM520N%26RM530N_Series_AT_Commands_Manual_V1.0.0_Preliminary_20220812.pdf)\nI added a [copy](./public/assets/docs/Quectel_RG520N\u0026RG52xF\u0026RG530F\u0026RM520N\u0026RM530N_Series_AT_Commands_Manual_V1.0.0.pdf) of the manual to the repo for completeness. No copyright infringement intended though. \n\n\n\n\n### Limitations | Future work\n- Only a subset of the AT commands are supported. Trying to use the `sendATCommandAsync(\u003ccommand\u003e)` with arbitrary commands may result on wrong parsing or the program hanging infinitely ( this is the case of advanced commands to perform HTTP requests). Problems have been identified for: `AT+QHTTPCFG=\"contextid\",1`  that requires additional arguments passed in several lines.\n- No support for parsing neighbouring cells (i.e.  missing parsing for the command `AT+QENG=\"neighbourcell\"`).\n\n\n\n### Tech Stack\n![NPM](https://img.shields.io/badge/NPM-%23CB3837.svg?style=for-the-badge\u0026logo=npm\u0026logoColor=white)\n![NodeJS](https://img.shields.io/badge/node.js-6DA55F?style=for-the-badge\u0026logo=node.js\u0026logoColor=white)\n\n![HTML5](https://img.shields.io/badge/html5-%23E34F26.svg?style=for-the-badge\u0026logo=html5\u0026logoColor=white)\n![CSS3](https://img.shields.io/badge/css3-%231572B6.svg?style=for-the-badge\u0026logo=css3\u0026logoColor=white)\n![JavaScript](https://img.shields.io/badge/javascript-%23323330.svg?style=for-the-badge\u0026logo=javascript\u0026logoColor=%23F7DF1E)\n\n### Troubleshooting\n- The Raspberry PI has been set up to init without graphical interface, run `startx` in the command prompt if you need to use the GUI in the device.\n\n\n\n\u003chr/\u003e\n\u003cdiv align=\"center\" \u003e\n\u003cimg src=\"https://github.com/user-attachments/assets/3dc5878a-aafc-4b55-aa1b-b9d3039faf32\"  width=\"50px\" height=\"50px\" /\u003e \u003cbr/\u003e\n  \u003ch3\u003e InMap - Indoors Signal Mapper Suite \u003c/h3\u003e\n\u003c/div\u003e\n\u003cp align=\"center\"\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cimg src=\"https://github.com/user-attachments/assets/9f964717-fbb2-4d28-ae00-e2a5c2ecc507\" alt=\"App screenshot\" /\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e \u003cimg src=\"https://github.com/user-attachments/assets/cdec1120-39aa-4181-87b6-d190dc953727\" alt=\"Web screenshot\" /\u003e \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cimg src=\"https://github.com/user-attachments/assets/26d1bc26-7552-4698-85ee-442a08ebe180\" alt=\"Pi-measurements screenshot\" /\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e🔗\u003ca href=\"https://github.com/espaciosoa/inmap-app\"\u003e  Android App \u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e🔗\u003ca href=\"https://github.com/espaciosoa/inmap-web\"\u003e Web visualizer \u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e🔗\u003ca href=\"https://github.com/espaciosoa/inmap-pi\"\u003e Precise measurement module for Raspberry-Pi\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fespaciosoa%2Finmap-pi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fespaciosoa%2Finmap-pi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fespaciosoa%2Finmap-pi/lists"}