geolocator (Software defined GPS) final evaluation

Hi everyone,

with this blog post I would like to explain the full Google Summer of Code Project as a final post. For people who haven’t read over the geolocator (Software defined GPS) project before, it might be interesting to read these three blog posts at first:

– geolocator (Software defined GPS) (english)[1] and (german)[2]

– geolocator (Software defined GPS) first evaluation (english)[3] and (german)[4]

– geolocator-software-defined-GPS-second-evaluation (english)[5] and (german)[6]

Otherwise I will give in the following a short overview about the project structure to remind you of it. I structured the Google Summer of Code project into 3 main subprojects:

web backend,

– The web backend named sgps-core is a service, which should give requested clients their geo position.


– The idea of gps-share is to create an udev device, which provides NEMA-formata protocols over tty addicted on information, which is received from the above mentioned backend.

LEDE Package,

– The intention behind this subproject is to develop a new package for LEDE called geolocator, which should provide the geo position of LEDE devices.

Now I would like to give you a full state of each above mentioned subproject. Firstly I will explain about the web backend and finally a peroration including my valediction as a Student by Google Summer of Code.

web backend

Generally the backend service receives over the OpenWLANMap[7] App from mobile phones the mac addresses of surrounding wireless networks linked to GPS positions. This information will be stored into a database. If a device like a WiFi router requests its position, it will send surrounding Wireless mac addresses to the backend and get back a geo position, which is calculated from these information in the database.

The new web backend called sgps-core[8] is an API-core, which should replace the old backend. The old one consists of a collection of different programs in different program languages. sgps-core includes a fully backwards compatibility to the old openwifi API[9] for requesting a position. sgps-core is written in Golang, which processes a lot faster than the old API, which is written in Ruby. sgps-core is more secure because it checks and take only requested strings, which contain only comma separated macaddresses with 12 hex characters.

As a fallback feature, sgps-core is able to receive coordinates from unknown WIFIs by requesting them on Mozilla Location Service (MLS)[10] if there are no db entries for that WIFIs. The position for clients will be returned in form of latitude and longitude. As a quick reminder, here is the schemata from the first post, which represented the the functionality of sgps-core:

The sgps-core solved a problem about calculating the position. The old method counts the average of all latitude values. Analogous for longitude. The new method calls geographic midpoint calculation and needs 4 parameters lat0, lon0, lat1, lon1 (give two take one) which will be explained in detail in following:

deg have to be replace with latitude or longitude value.

rad = deg *π / 180 <- Generally conversion from degrees to radiant.

dlon = (lon1 – lon0) * pi / 180

lat0 = lat0 * π / 180 <- lat0 from degrees to radiant.

lat1 = lat1 * π / 180 <- lat1 from degrees to radiant.

lon0 = lon0 * π / 180 <- lon0 from degrees to radiant.

Converting into Cartesian coordinate system.

Bx = cos(lat1) * cos(dlon)

By = cos(lat1) * sin(dlon)

Calculate new position reference to sphere and Converting back from Cartesian coordinate system into new latitude and longitude:

lat2 = atan2(sin(lat0) + sin(lat1), (cos(lat0) + Bx)² + By²)^(1/2))

lon2 = lon0 + atan2(By, cos(lat0) + Bx)

On this point it is also possible to use a ellipsoid to increase the accuracy of positions. This may be interesting for long distances. For short ones like from seen wireless networks, it is not really relevant.

Converting back to degrees:

deg = rad / pi * 180 <- Generally conversion from radiant to degrees.

lat2 = lat2 / pi * 180 <- lat2 from radiant to degrees .

lon2 = lon2 / pi * 180 <- lon2 from radiant to degrees.

In the last few weeks, I spent a lot of time on discussing with the current server administrator of to deploy the sgps-core on the server for a test environment. But he did not have much time, so we decided to migrate the to our Nordwest Freifunk infrastructure to make the administration more accessible for other people. In my last report I wrote “I will release in the next few days a first version”. This could not be done because of the above mentioned discussion. After the migration I can test that backend on huge databases and compatibility to the DBS. The current code can be found here [11]. For people who want to try the sgps-core please check out the following URL[12].


The Idea at the beginning of GSoC17 was to write a program to provide GPS NEMA-formats over a tty udev device. The information for the GPS NEMA-formats should come from the above mentioned sgps-core. As I told in the first blog post I discussed with some people from the Mozilla Location Service Malinglist and it turned out that something similar was already exist called geoclue. To avoid developing redundant software I decided to drop this idea. Instead of it the new plan was to build support for native GPS in gps-share[13], which is an add-on for geoclue. But during the Google Summer of code I had to focus more on the both other subprojects because they are more important, especially for Freifunk. In my peroration I will tell about the future plans, especially for gps-share.

LEDE Packages

The third subproject was to create some opkg packages for LEDE[14] and similar Frameworks. The main package called geolocator provides the geo position of the device via UCI[15]. Positions should be received from the above explained sgps-core. The 4 other packages are only for Gluon[16], which add the configuration options of the geolocator to the Web-interface.

This month I mainly worked on the LEDE Packeges. At the beginning of the august I sent a merge request to Gluon for integrating the Gluon-geolocator[17]. The containing geolocator program was written in ash shell code. While reviewing and discussing about the merge request, I realized that I had to rewrite the program from shell to lua code because Gluon mainly work with in lua written programs. You can find the shell code here[18] and the Lua version here[19]. At the moment I am waiting here for another review and subsequently merging.

The other packages for the Gluon Web-interface are also already in process. The first idea was to create a detection of installed packages to show related configuration options on the Web-interface. This idea was dropped because I found a better solution. The problem is detecting packages on runtime, which means many extra code on Routers, which only have 4MB Flash for example. So I decided to generate the package with their options on compile time. These packages are:





The main package is gluon-config-mode-geo-location, which is already exist in gluon, but with a difference Web-interface. Each package should either integrate an open street map or the geolocator options. Integrating both are also possible. For communities which would like to stay on the currently variety of functionalities, it is also no problem not integrate any of these extra options.

Here is how the new packages look like:

I wrote some C++ programs, which generate me the Lua code for the Gluon Web-interface, which is written in Lua. Base on preprocessor variables, the amount of options for each package will be included into the Lua output from the C++ program. These preprocessor variables will be set by selecting one of the above packages. Also PO files for the translation will be generated in the same way. A merge request of the above new packages can be found here[20] I am still working on it.

Peroration and Future plans

Now I am coming to my peroration.The last 3 months were really awesome, just like last year as a student on the Google Summer of Code. I would love to recommend this great opportunity for not only students but also for open source organizations. Students can not only learn a lot of new things but also meet new great people, make new friends and take part in many events. For example: at the beginning of august I was on the SHA2017[21] (Still Hacking Anyway) and had a meetup with some Freifunk communities there. We had a great discussion about a lot of technical stuffs and a nice time for socializing. The SHA2017 took place in Netherland nearby Amsterdam. Another example is : this week I flew to Spain to start my exchange semester. Coincidentally a student from Germany who I met at the beginning of the GSoC17 in Berlin on the WCW[22] (Wireless Community Weekend) is also doing an exchange semester in Spain. We have already emailed each other and planned to meet up in the next months, probly in Barcelona or any other places. As I said above, this is my second time as a student on the GSoC, which means this is also my last time and sadly I have to say goodbye to GSoC as a student now. But maybe next year I can work as mentor to support other students in their great opportunities.

Back to the projects, as i said I’m still working on it. I will finish the Integration into Gluon and LEDE and continue developing sgps-core integrate new features and migrate the infrastructure to a better server. I would like to contact Zeeshan Ali, the maintainer of gps-share and try to help on this project as well. Also I am still working on the hoodselector which is my Google Summer of Code project from the last yeah. You can read about it here[23]. The hoodselector should also integrated into Gluon but it requires for sure a few weeks of work to integrate VXLAN on it. A merge request for can be found here[24].

Also I would like to say thank you to my Mentors Clemens John from the Google Summer of code 2016 and Johannes Rudolph from 2017 and especially to Andreas Bräu who works so hard on the Freifunk Org for many years to give students these opportunities to be a part of the Freifunk Community.


























PowQuty Live Log GSoC 2017 Final Update

This is the last blog entry in the series of Google Summer of Code project updates. It will describe, what has been done and what is left to improve in the future in the PowQuty project.


PowQuty is a power quality monitoring tool, which can be installed on a router running LEDE or OpenWrt. The router can be connected to an USB oscilloscope providing measurements which powqutyd will process and provide to the user in human readable form.
All this was tested on a x86 based LEDE router.

GSoC 2017

During this Google Summer of Code a live log functionality was added to PowQuty to provide information on power quality events. These events are:

  • voltage dip of 10% – 90% of the reference voltage on the measurement signal
  • voltage swell > 110% of the reference voltage on the measurement signal
  • voltage dip < 10% of the reference voltage on the measurement signal
  • > 5% of the measured values of one specific harmonic are over the defined threshold
  • On event occurrence important information like time, duration and event type will be written to a log file and presented in the extended luci app.

    As shown in the above picture, the interface provides a traffic light like color system behind these events, green indicates everything is within the EN50160 power quality norm. Yellow means, that 80% of the maximum time per week is already reached, red means, that the norm was violated during the last week.
    In addition to log writes, notifications are send out with Mosquitto. Mosquitto is a message broker using the MQTT protocol. It provides a publish/subscribe model, which allows a central server to subscribe to a topic and clients to send out messages to the server with a topic. Mosquitto was already in use in powquty but was extended for EN50160 event notifications. This will allow a central logging of bigger power supply networks, monitored by multiple devices.

    As another option Slack messages can be send by powquty now. Slack is a messaging program, using (as one option among many) webhooks for interaction. Everyone with the webhook can send messages to the team. Sending out messages allows a user to react quickly to changing situations, or get immediately informed on power event occurrence.

    Beginning with pull request 20 [] I started to implement these features.
    First an option was developed to read measurements from a file, as most power supply networks are pretty stable and wont provide many opportunities to test event handling in powquty.
    Afterwards slack and MQTT notifications where added.
    During testing of mosquitto event messages, some seemed to be lost on intervals with many En50160 events in a short period(sometimes more than 35 events per seconds). The solution seems to buffer all events before sending.
    Something similar happened with Slack. Slack only allows one message per second(short bursts excluded) [rate-limits].
    Buffering events would resolve this problem as well. An option for live email notification was considered at first, but was dropped as spam protection would stop most of the messages and probably list users as spammers.
    The last step was to add the traffic light system to the luci app, to enable users without knowledge of the norm to get an idea of the power quality of their power supply network.
    In addition a slack library was written [libwebslack] to send slack messages from PowQuty.

    What can be improved
  • As mentioned before event buffering is needed and will be added after GSoC
  • Email notification in form of a weekly summary
  • More Error checking and handling
  • improving libwebslack to not use libcurl to reduce its size
  • provide libwebslack as OpenWrt/LEDE package, for easier future use
  • Finally I have to thank Dr. Thomas Huehn for being my mentor and Freifunk for their work they do and especially for being a mentoring organisation for Google Summer of Code.
    Last but not least I would like to thank Google for making this all possible.

    If you want to review some of my earlier posts:

  • Introduction
  • First Update
  • Second Update
  • Best regards

    netjsongraph.js – Google Summer of Code (GSoC) 2017 summary

    Throughout the last three months, I was quite fortunate to work for Freifunk on netjsongraph.js under the guidance of my mentor Federico Capoano. Thanks for this invaluable experience that I learned a lot of knowledge and use them in a practical project. Here is a summary of the work I have done during the Google Summer of Code (GSoC) 2017.

    Google Summer of Code project page


    netjsongraph.js is a visualization library for NetJSON, a network topology data format. The main goal of netjsongraph.js may be concluded in below three lines (more details you can see in GSoC 2017-netjsongraph.js: visualization of NetJSON data):

    • Apply the modern front-end development tools and add tests workflow (#1, #45)
    • Rewrite it with WebGL (#11, #29, #39, #42, #47)
    • Improve the performance (#41, #44, #46)


    Github Repository :

    Examples on GitHub pages:

    You can browse all examples on GitHub pages. Some screen shots of the application:
    basic example
    performance example
    The force-directed layout is usually used to visualize network data. It offers insights on the relationships between nodes and links. The previous version of netjsongraph.js is implemented by d3 and it’s rendered using SVG. It would be very slow if there were thousands or ten of thousands nodes or links. So I have to embrace the WebGL speeded up by GPU to have a better performance.

    I have recorded my work in the blog every milestone:

    BTW, It’s a great management method to make members submit weekly reports and blog posts in Freifunk.

    During the three months, there have been 116 commits from me. I created a big Pull Request include them:
    netjsongraph.js #48
    netjsongraph.js project panels
    Almost all goals have achieved:

    • Published a minor version
    • Improved development workflow
    • Tests Added
    • Refactored visualization by Three.js and d3-force
    • Added more interaction like hover (show nodes tooltips), click (show nodes or links information panel), pan and zoom
    • Improved performance

    Especially on performance aspect, it runs efficiently on Chrome reached 60FPS under 5k nodes and 10k links. And if you don’t wanna animation, you can choose the static rendering layout.


    I also encounter some challenges I never met before.

    Event binding and handling

    As you know, WebGL renders all objects in one canvas tag. How to bind events on every geometry? You should use the Ray casting. Raycasting is used for mouse picking (working out what objects in the 3d space the mouse is over) amongst other things. So you can know which geometry your mouse over and add some interaction effect.
    There are thousands of objects and every object has several events you should handle, I had to develop an event controller to manage it.


    The bottleneck in this visualizer is performance(#41). I tried many methods to improve it include:

    Reuse geometry and material

    However, the color of every node is different and the one link should highlight itself when it hovered, so the material should be independent and can not use in common.

    Combine the mesh

    Same problem with above. It’s not flexible to combine them to one mesh, different nodes and links should have different positions.

    Static rendering

    Make calculation before rendering, so there is no animation and repaint.

    Using Web Worker

    Web Workers is a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface. So put static layout calculation into it will be efficient.

    Force-directed algorithm

    There are different complexity and cost in the different force-directed algorithm. The Force-Atlas2 algorithm has some benefits over the force layout implemented in d3-force. So current version may be refactored by an advanced algorithm in the future.

    What is left to be done

    • Add optional geographic map (#40)
    • Using Force-Atlas2 algorithm

    More interactions and features should be added, and performance may be optimized by using new algorithm. I’d like to continue developing this project after GSoC.

    In the end, thanks for the great patience and guidance from my mentors. Thanks for Google to provide me with this rare chance to contribute to an open source community together with awesome members from all over the world. I really appreciate this invaluable experience accumulated this summer and I believe it will have the profound impact on my career and life.

    GSoC 2017 – Attended Sysupgrade – Final evaluation update

    Hi Freifunk,

    This is my last post within this years GSoC. I’ll cover the progress, challenges and future of the project.

    Direct links to the work I’ve done this GSoC:

    First a small reminder what the project is about: Enable end-users to update their routers to new releases or bulk update installed packages via a simple click in the Luci web interface. The magic lies in a server producing sysupgrade images with the same packages preinstalled as installed on the router. That happens on demand when triggered via the web interface.The image is downloaded securely via encrypted HTTP as the used browser has all certificates installed. The router does neither need certificates nor a correct running clock.



    At this point I’m very happy to announce a test (and usable) version of the attended sysupgrade setup. All created package recipes were accepted into the official repository and are compiled within the daily build cycle. The server runs fine obeying the described API at the Github page. Images are build within a few seconds if the request appears for the first time. The server stores previous requests and forwards to existing images instead of building it again. This reduces significantly the amount of build images due to the likely case of identical images being requested again. In addition some basic information are offered via the web servers status pages.

    The server is implemented in Python3 using flask for request routing and template rendering. While that’s only the tip of the iceberg behind the server lays a rather complex PostgreSQL database validating requests, checking for package changes or transforming packages when updating to another main release. More on the transformations later.

    Images created on the server. A click on manifest shows all installed packages with version. All snapshot builds are deleted midnight UTC.

    To try the the server at have a look at the demos I prepared. Continue reading “GSoC 2017 – Attended Sysupgrade – Final evaluation update”

    GSoC: Improving nodewatcher data representation capability (update 3)

    I have been working on improving the wlan-slo main page. This page has not been updated in a long time and it is crucial at introducing new people to mesh networking.

    Continue reading “GSoC: Improving nodewatcher data representation capability (update 3)”

    GSoC 2017-netjsongraph.js milestone 2

    After a month of efforts, netjsongraph.js has been greatly improved.
    First, I added some API and options are compatible with previous versions, except those that can not be added to the WebGL element. Followed by updating the documentation and some examples so that users can better understand and try out our projects. Finally, I have optimized interaction and performance.

    netjsongraph dark theme
    netjsongraph dark theme


    • added highlight effect on nodes and links when hovered.
    • added tooltips with node information
    • added pan and zoom interaction
    • added node and link information panel when clicked
    • adjust the size of the canvas when the window resized


    The large part of the performance of force-directed layout is consumed in each element position calculation in every tick. So if the position calculation of the elements is before canvas rendering, it is effective to reduce the performance loss.
    So I made a static layout, there is no animation when rendering, directly render a static force-directed layout in the page.


    Besides, I have refactored the event controller, in order to make zoom and pan or other events added easily.
    But now the overall rendering results are not good as our expected. There is a little lag in animation, I currently have no idea about the reason, perhaps because this is not best practice of three.js. In the next stage, I will focus on solving performance problems and improving the visual effect.

    Next Plan

    The links below may be useful:



    Hi everyone,


    I am now taking you over my second evaluation. A German version of this blog post can be found here [0]. For people who did not read over the geolocator (Software defined GPS) project before, here is a link to the project introducing (english)[1] and (german)[2]. The first evaluation from last month can be found here (english)[3] and (german)[4]. First of all I would like to tell you about the web backend:


    Web Backend

    As I said it in the blogpost before, the new web backend should replace the old one.
    The current web backend consists of a collection of different programs in different programlanguages. The new one is written in Golang it has a fully backward compatibility. The new web backend is more secure.  It checks all requested strings at the end of the url that they contain only comma separated macaddresses with 12 hex characters, as a validation check.


    Also the new web backend fix an issue by calculating the requested position. The method before just adds all latitude values and devides them over the amount of positions. Same for longitude. The new way is a geographic midpoint calculation. First the lat/lon values will be converted into radius and then the radius will be converted into a Cartesian coordinate system, after that the midpoint calculation will be done and will gave us a lat/lon in the form of radius and the values will be converted back into degrees, that is all.


    The web backend has a new feature which should help to enhance the position quality. If there are BSSIDs unknown in the database of, the new backend sends an extra request for the unknown BSSIDs to Moziller location service [5] and brings that information into the calculation of the response.


    At the moment the new web backend is being tested. In the next few days a first version of the new web backend will be released. The current code can be found here [6].


    LEDE Package

    The last project is to build packages for LEDE and send merge requests to Gluon. The idea behind that is, for WiFi routers and other WiFi devices to be able to automatically receive their own position. This could be a nice feature for mobile Freifunk Routers. It could also provide a good alternative instead of setting positions by hand. A first version of that package is here [7].


    For the integration in Gluon I plan 4 new packages. The first one is the gluon-geolocator, which depends on gluon-node-info and provides the programme with the capability of receiving geopositions based on surrounding WiFis.


    The next 3 packages are just for the Gluon configmode. The configmode is a state that begins at the initial start of a Gluon router and the owner of that router can configure it over a LAN connection.
    I would like to integrate the following 3 packages within the gluon-config-mode-geo-location.
    They are named:


    As their names indicate, the package gluon-config-mode-geo-location-with-geloc-map should integrate the options of the geolocator and an OSM map into the configmode. The other 2 packages, gluon-config-mode-geo-location-with-map and gluon-config-mode-geo-location-with-geloc should either integrate only an OSM map or just the configuration options of the geolocator. Also the package gluon-config-mode-geo-location should be able to and will show the current location interface without any map or geolocator.


    A merge request of the above new packages will follow soon. Some of the gluon-config-mode-geo-location extensions are currently not finish yet.


    In the next few weeks I would like to finish the integration into Gluon, as well as continuing to develop the new web backend and releasing the first version of it. There are many ToDo points currently open e.g. Multicore functionality, optionally other geographic midpoint calculations. At the beginning of August there is the SHA2017[8], which I will use for a marathon session.


    With best wishes
    Jan-Tarek Butt


    GSoC 2017 – wlan slovenija – Report 2 – HMAC signing of Nodewatcher data

    What’s been done

    The first blog post that describes the idea and goals can be read here and the first update here.

    The data that the nodewatcher receives from nodes had no signature, so anyone could intercept the packets, change the content and send them on their merry way. Authentication using SSL certificates was already implemented, but a lightweight, fast solution, that doesn’t require the use of big libraries like OpenSSL and any extra dependencies on nodes was desired. That means two things. First finding a good sha256 implementation or writing my own. Some libraries implement extra precautions to prevent side-channel attacks, which take advantage of some physical characteristic of the implementation. Even then not all implementations are safe depending on the system on which the algorithms run. It was decided that in this context these attacks don’t bother us too much and the attacker would need physical access to the device anyway. Therefore Brad Conte’s open source implementation was used.

    The second part involved writing the hash-based message authentication code. I tried to optimize the algorithm as much as possible saving space and time. After combining both parts the correctness of implemented HMAC-sha256 was thoroughly tested using official test vectors.

    The extra option to select the desired authentication was added to nodewatcher-agent, with SSL certificates being the default. If HMAC signing was selected, a HMAC signing key needs to be provided. The signature converted to base64 is then inserted in to the message header and checked when received by the nodewatcher.

    What’s next

    Now I will start working on IPv6 support for the Tunneldigger.

    I am contributing using my github account.

    Forward! Good luck!

    PowQuty Live Log Second Update

    It’s been nearly a month since my last update on the PowQuty Live Log project and i would like to tell you, what has been done
    so far and provide information on what will be done in the next month.

    PowQuty got updated, to support Slack and mqtt event notification and can already be used in the current PowQuty version.
    In addition to this, there have been some bug fixes during the last month and some new features were added.
    On event occurrence the event gets stored in a csv file and each entry is displayed in the luci-app. To increase the usability,
    a traffic light system will be added, which will show for each event type its occurrence time and show if the current values
    are in violation of EN50160.

  • Green: Everything is ok, no violation
  • Yellow: Close to a violation
  • Red: This event time is in violation of the norm
  • The event messages contain a times stamp, the duration of the event and updated event Type information, as well as event type related
    information and GPS data.

    As receiving notifications or emails on every event occasion can get noisy, we decided to provide a weekly summary of the events in
    addition to the regular notifications.
    The user will be able to decide if he wants to receive this summary, every event, or both. We consider using the traffic light system
    here as well, to increase the readability and enable users to understand the quality of their power supply network, without a lot of
    knowledge of the EN50160 norm.
    We discussed individual intervals and keep it in mind as a possible later feature.

    Best regards

    Easy ubus Daemons with rpcd

    Libremesh /etc/banner

    In this article we will see how to create a simple ubus daemon with RPCd.

    Ubus is an amazing piece of software that allow inter-process communication inside and in between nodes.

    For inter-process communications it uses a common bus with synchronous and asynchronous calling, publish/subscribe and event paradigms.

    For in-between nodes communication it provices a JSON-RPC 2.0 Server (and I hope will do WebSockets soon!).

    For more information on how ubus works check out OpenWRT’s Wiki page.

    If you want to expose simple functionality to ubus (or you are prototyping an interface before creating an efficient daemon) you can use rpcd for this.

    This is a simplified example based on the one in the wiki

    $ cat << EOF > /usr/libexec/rpcd/banner
    # The RPCd interfaces with commands via two methods: list and call.
    case "$1" in
                    # List method must return the list of methods and parameters that the daemon will accept. Only methods listed here will available to call.
    		echo '{ "append": { "content": "str"}, "show": { } }'
                    # The way rpcd calls the methods is by calling your script like this: <script-name> call <method-name> << <json-input>
                    # So, in order to retrieve the called method, you need to read $2
    		case "$2" in
    				# And in order to retrieve the method parameter, you need to read stdin
    				read input;
                                    CONTENT=`echo $input | jsonfilter -e '@.content'` 
                                    echo $CONTENT >> /etc/banner
    				echo '{ "result": "ok" }'
    				# return json object or an array
    				echo -n '{ "content": "`; echo $(cat /etc/banner | text_to_json); echo '"}'
    function text_to_json() {
    JSON_TOPIC_RAW=`echo $1`
    JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\\/\\\\} # \ 
    JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\//\\\/} # / 
    JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\'/\\\'} # ' (not strictly needed ?)
    JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\"/\\\"} # " 
    JSON_TOPIC_RAW=${JSON_TOPIC_RAW//   /\\t} # \t (tab)
    /\\\n} # \n (newline)
    JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^M/\\\r} # \r (carriage return)
    JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^L/\\\f} # \f (form feed)
    JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^H/\\\b} # \b (backspace)
    $ chmod +x /usr/libexec/rpcd/banner
    $ service rpcd restart

    And then we can try the new daemon:

    $ ubus -v list banner
    'banner' @xxxxxxx
    $ ubus call banner show
    LEDE blah blah
    $ ubus call banner append 'Hello world!'
    LEDE blah blah
    Hello world!

    @Rundfreifunk comment suggested that if you want to use this RPC commands via JSON-RPC, you need to add authentication parameters.
    In this case, let’s suppose that we want to grant anonymous read access to the method.

    We could do that like this:

    $cat << EOF > /usr/share/rpcd/acl.d/banner.json
      "unauthenticated": {
        "description": "Alfred data types via batman-adv meshrouting",
        "read": {
          "ubus": {
            "banner": ["show"]

    The documentation related to ACLs can be found in this OpenWRT wiki page.