# __berry-frame__ ## A Framework for building
Raspberry Pi Applications
with a Web UI _( Gero Scholz, January 2020)_
## INTRODUCTION If you develop more than one application for small embedded computers you will quickly notice that more than 70% of your program code does not really deal with the application logic itself but with technical issues like accessing a certain device or handling communication between your Raspi and a web client. __berry-frame__ offers a way to separate all this generic technical stuff from the real application logic. The applications you build with __berry-frame__ are called _berries_. __berry-frame__ is not a "graphical tool for drawing your programming logic". It is based on a formal, structured description of the hardware components and their basic interactions. __berry-frame__ expects a so-called __hardware definition file (HWD)__ with a simple grammar based on JSON syntax. The HWD notation also establishes some standard rules for visual representation of hardware elements in the browser UI and for the general flow of information between UI elements and hardware devices connected to the Raspi´s GPIO ports. The overall structure is illustrated by two diagrams which show the physical aspects and the logical structure of __berry-frame__ ----- __berry-frame__ is written in _Javascript_. This means that we can use the same language on the server (running under NodeJS) and on the client (running in the browser). __berry-frame__ comes with a light-weight embedded web server. So there is no need to install/configure Apache on your Raspi.
As soon as things get more complex, you will have to provide some Javascript code (preferibly ES6 standard) to describe the logic of your application. The logical part of yor _berry_ works on the server. If you want to customize the UI you can also add code and resource files to the client side.
### A framework, yes, but hopefully not a bed of Procrustes! Using a framework means that you have to accept some decisions which were taken by the creator of __berry-frame__. While frameworks in former times esteemed themselves like the godfather of the application nowadays they try to be more modest, ideally "non obtrusive". __berry-frame__ is somewhere in the middle. It has a clear idea of a layered software architecture and takes control over hardware access and over the web server. But it gives you a lot of possibilities to hook into its skeleton or to extend it.
Think of __berry-frame__ being the __technical boss__ and you being the __chief of application__.
The question __How much declaration and how much dedicated coding do we want?__ is crucial for the design of a framework like __berry-frame__. An __example__: If you have a temperature sensor you may want to watch its value regularly and switch a LED to ON if it is too high or light a different LED if it is too low. The HWD (i.e. the hardware definition file of your _berry_) is powerful enough to define this behavior in pure declaratory style without any algorithmic coding. In a concrete case, however, it might seem useful to trigger the over-temperature signal only if there were three consecutive observations (slightly) above the threshold. If the value exceeds the upper limit by more than 10%, however, the light should go on immediately. This kind of logic would be a clear candidate for specific server-side, hand written application code of your _berry_. Similar rules apply to the UI. The declarations within the HWD allow you to place the current value delivered by the temperature sensor somewhere on the browser screen with all possibilities of CSS formatting. But if your _berry_ is a weather station you probably will like to use a rich set of pictograms in addition to the numeric temperature value. In that case you will have to add a new function to the client which receives the current temperature value from the __berry-frame__ framework and creates your desired visual representation. This may include Javascript code, CSS declarations, providing images and animations, sound, videos etc.
# Table of Contents
1) Main Features of __berry-frame__

2) How do I work with __berry-frame__?

3) Architecture

4) Customization

5) Supported Device Types

6) Hardware Configuration

7) Server, Master and Monitor

8) Client

9) Task structure

10) Installation

11) Sample Berries

12) Creating a Berry

13) License and Copyright

14) Security

## 1) Main Features of __berry-frame__ __berry-frame__ can be installed and run on a Raspberry Pi and on Windows. On Windows __berry-frame__ emulates the hardware peripherals ("devices") of the Raspi. The emulation can also be used on the Raspi itself, e.g. for replicable tests or if the hardware is not physically connected for some reason. But do not expect too much: The emulation is an aid for development and test; it does not try to resemble the behavior of real hardware devices by any means. __berry-frame__ consists of classes which encapsulate hardware devices, a web server, a registration service for servers and a generic web client. __berry-frame__ applications (short: _berries_) are formally defined by a hardware definition file (HWD, validated against a defined grammar) and one or more Javascript classes which have to be written by the application designer. __berry-frame__ comes with a generic web client which can display all supported hardware device types in 'basic optics'. Application specific code can be added to enhance and customize the user interface. __berry-frame__ clients can connect to more than one _berry_ (server) simultaneously. This means that a client can work as a control center for several _berries_ of the same type or even of different types. __berry-frame__ uses fast light-weight socket communication between clients and servers, providing full synchronisation of the physical hardware with all attached clients. __berry-frame__ works asynchronously for time-consuming hardware-related functions. __berry-frame__ comes with a registration service (__Berry Master__) to facilitate cooperation between multiple _berries_ (possibly running on different Raspis). __berry-frame__ is written in Javascript (ES6 syntax); the server part runs on Node.js, the client part runs in the browser. __berry-frame__ requires no installation (apart from Node.js and the required modules). __berry-frame__ is reasonably fast on modern Raspi hardware. It can even be used on older models with acceptable performance but you will observe _very long loading times_ (~30 sec.) there, possibly due to memory swapping in the loading phase. If you can accept that, the performance might be ok once it is up and running. __berry-frame__ is open source and can be used freely (see license chapter).
Sure, many useful features. But there must be some negative points as well?

Yes. There is a learning curve. It is easy to build simple applications. But complex applications with exotic devices will require you to extend the framework. This means that you must understand its architecture - which requires some effort, indeed.

__berry-frame__ puts (almost) all security aspects for your _berries_ into your hands. There are two features which will help you: (A) There is a commandline option which allows to suppress "critical features" like rebooting the raspi from the web UI. (B) There is a commandline option to restrict incoming connections to those which have been forwarded by a definable server. Using this feature you can protect _berries_ by installing a _reverse proxy server_ which is the only one allowed to talk to your _berry_ and which exposes a public port to the web. It is your responsibility to install such a server (typically: apache) and to care for its security (typically: htdigest).

### Why should I use __berry-frame__? * It makes your life easier. You only write the "net" code of your application. * It uses the same language (_Javascript_) on the server and on the client. * Running on _Windows_ during development speeds up the edit/run cycle significantly. * The formal hardware description is a good documentation for your project. A nicely formatted version can also be shown to the user in the browser. * You get benefits like a REST-like API for your application without much effort. * You get a starting point for building cooperative Raspi applications. * You do not have to care about communication between server and client. * You get a simple UI out of the box without any client-side programming. ##
2) How do I work with __berry-frame__? To build your own _berry_ you must provide a formal description of the hardware elements connected to the GPIOs (or USB ports) and you must provide a Javascript class which describes the specific behavior of your system. __berry-frame__ comes with a bunch of classes which encapsulate certain types of hardware elements, like push buttons, LEDs, LED strips, motion sensors, speakers and microphones. The _lower layer_ of these encapsulating classes deals with __protocols__ like digital I/O, PWM, 1-Wire, SPI and I²C. The _upper layer_ deals with sensor/actuator specifics. If the type of hardware you want to connect is already there, everything is fine. If you want to connect other hardware elements you will need to extend the framework by a class to _encapsulate your specific type of hardware_. Doing this is not too complicated. __And without _berry_ you would have to write very similar code anyway.__ As said before, __berry-frame__ supports emulation of Raspi hardware elements under Windows. So, if you are extending the framework you will also have to provide (minimalistic) code to do some sort of emulation (returning random values or whatsoever). For a new type of hardware element, say: a motor, you will also have to provide a reasonable optical client representation with HTML/CSS/JS.
Enough of theory and preambles? Maybe you want to go to the "Installation" chapter now. But sooner or later you will notice that a good understanding of __Berry´s__ architecture is helpful. So maybe you better continue reading here, now? ##
3) ARCHITECTURE __berry-frame__ has a layered architecture. Apart from the physical hardware we have three software layers: __Hardware Management__, __Web Service__ and the __Web User Interface__. ``` ----------------------------------------------------------------------------------------- PHYSICAL HARDWARE HW Physical Hardware connected to the Raspi ----------------------------------------------------------------------------------------- HARDWARE MANAGEMENT HP Hardware Protocol Encapsulation HA Hardware Access, Device Type Encapsulation HC Hardware Configuration and Control ----------------------------------------------------------------------------------------- WEB SERVICE WS Web Server ----------------------------------------------------------------------------------------- WEB USER INTERFACE WC Web Client ----------------------------------------------------------------------------------------- ``` More details are shown in the following diagram: ## 4) CUSTOMIZATION As can be seen in the diagram each software layer has a part that is defined by the __Berry Framework__ and an (optional) part that can be added/configured according to the needs of your _berry_ application (shown on the right hand side in red color). The implementation of a layer can also include publicly available _third party Node.js modules_ (shown on the left hand side in orange). The hardware layer uses libraries for various protocols (like GPIO, I²C or SPI) and for certain device types (e.g. WS2801). The web server uses libaries for http handling and socket communication. The web client uses a very common library called _jquery.js_ and another library called _commonmark.js_ for rendering MarkDown syntax to HTML. ### Let us briefly look at each layer: * __HP - the protocol encapsulation__ - is fairly complete; It comprises: * _GPIO_: general purpose tri-state input/output pins with configurable pull up/pull down * _PWM_: hardware controlled pulse width modulation (only at supported pins) * _PWM_: software controlled pulse width modulation (most other GPIO pins) * _1Wire_: 1 wire protocol for sensors * _SPI_: serial peripheral interface (SPI0 and SPI1), a master-slave connection * _I²C_: inter-integrated circuit protocol, a more flexible and more complex master-slave connection * __HA - the device access layer.__ Details on the currently supported types can be found in the next chapter. If you want to use a device of a type which is not yet supported you will have to add new classes to this layer. This could be a stepper motor, a RFID reader using SPI or another 1-Wire sensor or whatever you need. * __HC - the hardware control__ - is a generic module which is mainly driven by a JSON file containing the hardware description (HWD) which you must provide. The HWD must contain all hardware elements (type and properties) of your _berry_. It also contains elementary layout hints for UI representation and settings for automated information flow. If you add new classes to layer HA you have to add small pieces of code to Hardware.js. in layer HC to enable the new types. * __WS - the web server__ - will in many cases have to be extended by a class which contains the specific logic of your application. That class should be derived from "App", which is provided as a parent class by the __berry-frame__ framework. This class does not sit in the framework directory tree. It is rather a direct part of your _berry_. * __WC - the web client__ - could be extended if you feel that the standard way to display the hardware peripherals of your _berry_ is not adequate for your needs. We recommend to separate your code from the generic web client, but right now there are no built-in mechanisms for the coexistence of the generic Berry web client and your own client. In some cases you may want to replace major parts of the generic client and only retain its functionality for socket communication.
If you make extensions to the framework which can be useful for others - especially in the HA layer, we encourage you to contact the author so that your contribution can be added to the framework. So, if you added support for more sensors or actuators, let us know! In such cases please also provide an extension to the generic client (WC) so that the new elements can be visualized adequately in the browser UI. You may also want to add _pure software application components_ like e.g. a _scheduler for timed tasks_ or _abstract devices_ like a _persistent memory_ that could store configuration and calibration settings which survive a reboot of the Raspi. Of special interest are contributions regarding the control of _physical displays_. ##
5) SUPPORTED DEVICE TYPES ( layer: BHA / AHA ) A list of supported device types is shown on the command line if you simply call ``./berry`` from the command line. Depending on the current version of __berry-frame__ it will show something like ```` Action A selection of options which represent commands (shown as a combo-box in the WEB UI) ADS1115 A four channel analog-to-digital converter based on I2C protocol (0x48) Button A push button connected to a GPIO (configured as input) with configurable debouncing Display A (virtual) generic character display only usable in the WEB UI DS1820 A temperature sensor using the 1-Wire protocol FrontPanel A virtual representation of the physical housing, used in the WEB UI for relative positioning of all UI widgets Label A text label used on the virtual FrontPanel in teh WEB UI LED A light emitting diode connected to a GPIO (configured as output) Microphone A microphone (mono) MPU6500 A motion and acceleration sensor using I2C protocol (0x68) PWDevice A pulse width modulated device, based on HW-controlled GPIO or on soft-GPIO Speakers A pair of speakers, connected via audio jack, I2S, USB or Bluetooth Task A background task which triggers actions in a certain interval TextInput A (virtual) rectangular text input area, usable in the WEB UI WS2801 A LED strip with individually controllable RGB triples, uses SPI protocol ```` Please notice: If you connect speakers via I2S the hardware controlled variant of ``PWDevice`` cannot be used because I2S uses both hardware PWM signals of the Raspi. It is planned to add more device types, like ```` step motor more 1-wire sensors force sensors DA-converters relais ... ```` ## 6) HARDWARE CONFIGURATION ( layer: BHC / AHC ) The hardware configuration for a _berry_ is described in (slightly extended) JSON notation (*.hwd files). The framework parses the HWD file and "builds" the hardware by assembling the necessary classes and connecting their information flow. The HWD provides general information about the application (like its name, type, textual description and revision number) and a list of its __elements__. Elements are physical parts of the hardware but can also be abstract "Actions", which appear only in the UI and do not have a physical correspondence. Apart from technical details like GPIO numbers, debounce times etc. the HWD also contains layout declarations for the representation of each element on the browser screen ("virtual front panel"). Elements have a unique identification (property:id); in addition there are some *built-in reserved ids:* - ``server`` : the built-in web-server - ``hardware`` : the hardware as a whole - ``app`` : the application as a whole - ``api`` : the application programming interface as a whole HWD files allow to define simple connections between, say, a Button and other elements like LEDs. Therefore in some cases you could even define a Berry application without a specific application server class. See our "Hello" _berry_ as an example. ### 6.1) Extended JSON Syntax HWD uses JSON syntax. In addition the following rules apply: * both types of comments (double // and /* .. */) are allowed * attribute names must not be enclosed in quotes; this means that you write something like {name:"foo"} and not {"name":"foo"} * superfluous commas are allowed and will be ignored * strings can be broken into multiple lines by simply writing them line by line, each part enclosed with quotes * You must not use the percent sign (%); use "%" instead ### 6.2) Basic structure ``` { title: "A text which will appear in the web client´s head region." "It can contain arbitrary HTML", type: "the type of the application; it should start with a capital", desc: "A description of the application which is shown in the web client on user´s demand." "Arbitray HTML, slashes must be escaped.", port: a valid (free) port number, appClass: "empty OR the application class name (which should equal the application type)", rev: "A string to identify the hardware revision", img: "file name of an image which will be shown in the web client" "the image is searched in "client/hardware//", elms: [ an array of Elements ] } ``` Elements are (mostly) _physical_ devices of the application which are represented in the web client. A hardware definition must contain exactly one element of type "FrontPanel". All other elements are (absolutely) positioned relative to this element. Element types have some basic built-in CSS formatting for the client which can be overwritten in the "style" attribute. ### 6.3) ELEMENT definitions: ``` { type: "a valid element type like "+ "FrontPanel,Label,"+ "Button,LED,PWDevice,WS2801,MPU6500,TextInput,Display,Microphone,Speakers,"+ "Manual,Action,..", id: "a unique literal to identify an emement; the id is typically _not_ visible to the user", name: "a name to describe the element; the name is visible to the user for most element types", title: "a help text which is displayed on mouse over", gpio: a GPIO/BCM number to identify the pin connected to the element, cable: "a description of the cable(s) leading to the device, typically its color", color: "a CSS color which applies to the representation of the lement in the web client", style: "CSS definitions which describe the UI representation of the element in the web client", emulate: "true if an element is not physically available; if Berry is running on Windows"+ "this property is automatically TRUE for all elements" } ``` By typing ``./berry -a all`` you will get a lengthy JSON text which shows the HWD schema and the API for all elements (device types). By typing ``./berry -a LED`` you will get the same JSON text but only for the given device type. Some device types allow to define event handlers, e.g. Button allows handlers for the events ``down, up, downup, pressed``. Actions defined by an event handler have the following structure: ```` elm: "the id of the element to which the action refers", cmd: "the command which shall be invoked on the element", arg: "an object to be passed as an argument to the command", when: "a condition to allow/prevent execution", "the given value must match the result of the getValue() method of elm to allow execution", after: "start execution after the given time in msec (isolated timer)", delay: "start execution after the given delay on msec (timer linked to the element, may be updated while running)", once: "true/false: do /or do not update the delay timer linked to the element while the timer is running" clear: "true: delete the timer linked to the element", ```` ## 7) SERVER, MASTER and MONITOR ( layer: BS / AS ) ### HTTP The Berry Server layer acts like a traditional web server delivering files.
Its URL handling is based on the following rules: * It redirects an empty URL to ``index.html``. * It treats URLs starting with ``/reg?`` as registration requests between a _Berry server_ and the _Master Berry server_. * It treats URLs starting with ``/api/`` as REST-API calls. * It treats an URL starting with ``/app/Master/`` as a reference to the _Berry Master_. * It treats all other URLs starting with ``/app/`` as a reference to your _application Berry_ * It treats all other URLs as a reference to the generic client of the Berry framework. ### Socket communication The Berry server establishes web socket communication with all clients and uses it for .. * direct responses to a client socket request, delivering hardware configuration and full state of the hardware * transmitting a list of active servers to a client * transmitting a list of inactive (startable) servers to the clients of the Master * direct responses to single ``getValue()`` requests of a client, delivering selected hardware status information * broadcasts to push changed state(s) of hardware elements to all connected clients ### Master Berry __berry-frame__ comes with a __built-in Master application__ which is in principle a normal _berry_ but has some special functions for maintaining a list of currently active _berries_ and another list of _berries_ which can be started via the _Master Berry_. ### Monitor __berry-frame__ has a watchdog mechanism which is called the _monitor_. If you start the _monitor_ it will regularly check if a _berry_ was terminated and said that it wished to be restarted. This means, of course, that a _berry_ going down for a restart must write suitable restart information to a place where the MONITOR will pick it up. This place is a file in BERRY_HOME named "restart.cmd". ##
8) CLIENT ( layer: BC / AC ) The generic client receives a copy of the HWD from the server and uses the layout information (CSS) contained in the HWD to arrange the hardware elements on the screen, i.e. painting the front panel with all its elements. As a mnemonic it also displays a photo (or schematic diagram) of the physical hardware. It also adds a large heading (configurable in the HWD) above the front panel The client can contact the REST API of its server _berry_, show syntax help and send single REST requests in a separate browser tab to the server. On request of the server it helps to establish a web socket connection with the server. Whenever the server sends new socket messages with changed state information the client will update values or colors in the UI. The client can also play sound files if told by the server. Whenever the user interacts with the browser UI the client will construct a socket message for the server describing the event (like "button x pressed"). The client monitors the socket connection and tries to re-establish it if the server disappears unexpectedly. The client offers the possibility to STOP (permanently) or STOP-AND-RESTART its server _berry_. The client offers an UPDATE service to install the latest version of the __Berry framework__. Regarding the Raspberry Pi computer itself the client can issue a command which will perform a REBOOT on the Raspi or a SHUTDOWN/HALT. The client can show the current MANUAL text (by clicking on the berry symbol in its top left corner). The client can show the HWD file to the user (probably only developers and expert users will be interested in this). The client allows you to download a ZIP file of the currently running _berry_ so that you can easily transfer it to another machine where the __Berry framework__ is installed. The client can show a nicley formatted PIN MAP which documents all physical connections to the hardware. The client can not only show the UI for the _berry_ it contacted initially. If a Berry Master is active and if the client´s server has connected to the Master, the client will be given a list of all active _berries_. It can then show their UIs as well. In fact it becomes a normal client for those servers - with the exception that it cannot stop or restart those other servers. ## 9) TASK STRUCTURE The following diagram shows the task management of __berry-frame__. Tasks are marked with a "colored button". Basically you have the following tasks * the MONITOR (cycle of 5 seconds) * The WEB-SERVERS of all active _berries_ serving HTTP * The WEB-SERVERS of all active _berries_ listening to SOCKETS * The WEB_CLIENTS of all connected browsers listening to SOCKETS of each server they are connected to ## 10) Installation You must have ``nodejs`` and ``npm`` installed on your machine. Create a home directory for your _berries_ (hereafter called 'BERRY_HOME') somewhere on your machine. BERRY_HOME will contain the _Berry framework_ itself and your own _Berry application(s)_. For an installation on Windows BERRY_HOME could be something like ___c:\berries___ For an installation on the Raspi you could choose something like ___/home/pi/berries___ Within BERRY_HOME call ``npm install berry-frame`` and wait until the process has finished. Then copy the binaries for ``berry``, ``monitor`` and ``onreboot`` from ``node_modules/berry-frame/bin`` to BERRY_HOME and make them executable (on Windows copy the resp. ``*.bat`` files). __berry-frame__ can (and should!) be installed on _Windows_ and on your _Raspberry Pi_. Start with the installation on Windows. It is easier and faster and you will need it for the development of your _berries_ anyway. ### 10.1) Test on Windows Unzip the _Hello sample berry_ (from ``node_modules/berry-frame/sample_berries/Hello.zip``) into BERRY_HOME. Within BERRY_HOME now call ``berry(.bat)`` and you should see a lengthy explanation on how to start __berry-frame__ from the command line. You will see chapters on Purpose, Version, Usage, Option, avialable _berries_ and some Notes. The text will end with an error message because we did not tell __berry-frame__ which of our _berries_ we want to start. Now let us call ``berry Hello -l 1" This starts the _Hello Berry_ and activates Logging. When the script starts, the first output line will contain the port number; in our case: 9001. The other lines of the Log tell you that __berry-frame__ found and parsed ``Hello.hwd``, assembled the modules necessary for the hardware configuration described in the HWD, started the Web Server (listening at port 9001), began to watch the state of a LED and tried to register itself at a _Berry Master_ which it expected to find on port 9000. There was no response but this is not a problem (it only means that you get no help for cooperation between multiple _berries_). __So, now the server is up and waiting for requests!__ It is time to open your browser and point it to ``localhost:9001``. "localhost" means that the _Hello Berry server_ is running on the same machine as the browser. So the browser does not have to search within your LAN or even within the internet. Instead it will use the IP 127.0.0.1 which is by convention always the IP of the local machine where the browser is running. Note: If you add the option ``-b`` or ``--browse`` when starting the _server process_, the default browser of your system will automatically open the correct URL. The browser will show a web page like this: But what happened to the command line window? It was flooded with a lot of messages! __Scroll up__ in the terminal window and try to understand what happened. You will see: * First it got an empty HTTP request from the browser which it interpreted as a request for ``index.html`` * Afterwards it received HTTP requests for ``BerryUI.css`` and some other files. This happened because ``index.html`` references these files as it needs them to work properly. When the browser sees those references it understands that it must request these files from the server. * Then we see the first SOCKET request issued by the _Berry Client_: It tells the "hardware" to "getAll". As a response the _Berry server_ sends a very long "hardware setup" message which contains the hardware configuration of ``Hello``. * As a next step the server automatically sends the current state of its hardware. In our case this is quite simple: The LED with the id 'led' is off, described by a value of 0. * The server tries another time to register itself at a Master but fails again (it tries to register whenever a new client contacts the server). * Apart from that we see that the web client requested two images; one of them can be seen on the right hand side of the UI; the other one is hidden at the moment. Switch to the browser and click on the small gray "Hello" button at the bottom left. * This will show a descriptive text in a yellow box and a large table with the pinout. And next to that table you will find the second image (the greenish raspi board) which had already been loaded in the step before. * And there is a list at the bottom of the table which explains every bit of the HWD. All this information was prepared from the HWD config information which was initially sent by the server. This means, on the other hand, that the client DID NOT HAVE TO TALK TO THE SERVER when you pressed the gray 'Hello' button. Click the small gray "Hello" button again to hide the additional information. * Again, this action did not affect the server. It is still sleeping and waiting for client requests. So let´s wake it up! Click on the "press and hold" button in the UI, hold it down for a moment, look at the server´s command window, and finally release the button. * The browser detected the _button down_ event, sent it as a socket message to the server as you can see in the server log lines. * Then the server talked to the virtual hardware (note that we are on Windows where there is no such thing like a real GPIO) which switched the LED #15 to "ON" (#15 is the GPIO number to which the LED is connected; note that GPIO #15 sits on physical pin #10, as the pinout tells us). * Now the server sends a broadcast to all clients with LED "led" having a value of 1. * Your client gets the message and switches the LED to "green" because it learnt from the former hardware setup message that the LED has a green color. * When you released the button another message travelled from the browser to the server and the LED went OFF. This new state was transferred back to the browser and (only then!) the browser replaced the green LED color by a dark gray to indicate that it is OFF now. Now you should open a second client in another browser or at least in another browser tab, so that you can see everything simultaneously: The two browser screens and the server log. Then press the button in one of the windows and see what happens! We recommend to experiment with this setting. You may also want to open the _Hello Berry_ from your mobile device. In that case your PC and your mobile device should be connected via WiFi and you must know the name or IP addresse of your desktop computer where the _Hello Berry_ is running. Assuming that your Windows machine can be reached under 192.168.0.44 you type http://192.168.0.44:9001 into the browser on your mobile device and you should see the user interface. In the command log you will see that the server now talks to all three clients, eagerly propagating status changes of the LED induced by any client´s action to all of them in near real time. Finally you should try out the other functions of the client. * Click onto the green letters "HWD" in the lower part of the screen. * Click onto the red raspberry icon in the top left corner of the UI to see this manual. * Click onto the green letters "API" and change the URL in the new tab to http://localhost:9001/api?id:"led",cmd:"toggle" refreshing the page should give you values 0 and 1 alternatingly. if you have a look at the web UI of ``Hello`` at the same time you will see the LED going on and off. The Log lines of the server will tell you that it received an API request and that it changed the LED state. ### 10.2) Installation and Test on the Raspberry Pi #### 10.2.1) Prepare SD card This chapter describes the installation from scratch. If you have your Raspi already up and running you may want to skip the first parts. If you do not want to use WiFi you can ignore steps marked with [WiFi]. In that case you should follow the steps marked with [LAN]. If your Raspi has a RJE45 LAN connector we recommend to use the LAN connection at least during installation as it is probably more stable and has better performance. As usual you start on a Windows PC to prepare the SD card: * download and install __Etcher__, __putty__ and __filezilla__ (or another ftp utility) * download __Raspbian lite__ from __raspberrypi.org__ * unzip the download * use Etcher to copy the unzipped img file to the SD card * release the SD card drive, remove the card and re-insert it; you should then see a drive called ``boot`` * add an empty file named "ssh" to the boot device (which is the root partition of the SD card) * [WiFi] add the file "wpa_supplicant.conf" to the root partition of the SD card. EXAMPLE: ``` country=DE # Your 2-digit country code ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev network={ ssid="YOUR_NETWORK_NAME" psk="YOUR_PASSWORD" key_mgmt=WPA-PSK } ``` #### 10.2.2) Initial configuration * [WiFi] make sure you have a Raspi with built-in WiFi or use a Wifi USB stick * [LAN] connect the RJE45 jack to your local network __Put the SD card into the Raspi and switch power on.__ * Stay on the PC and **connect to the Raspi via putty** * Use the symbolic name RASPBERRYPI or search in your network for that name and note the IP that was assigned to it by your network infrastructur. * Login with ``putty`` as user "pi" with password "raspberry". * configure __host name__, __localization/time zone__, __hardware interfaces__, and other items * you may also want to change the __password__ * also select __"expand filesystem"__ from the "advanced options" * close the config tool, reboot the Raspi and reconnect via putty: ```` sudo raspi-config ```` then reboot, update and upgrade your system: ```` sudo apt-get -y update sudo apt-get -y upgrade sudo apt-get -y update ```` * [WiFi] create a file named ``wifi_restart`` in /home/pi with the following contents: ```` #!/bin/bash ping -c2 8.8.8.8 > /dev/null if [ $? != 0 ] then ip link set wlan0 down ip link set wlan0 up fi ```` Make the file executable (``sudo chmod +x wifi_restart``) and make sure that this file will be started regularly, say every two minutes, calling ```` sudo crontab -e ```` and adding ``*/2 * * * * /home/pi/wifi_restart`` The last step is necessary to make sure that your Raspi will regularly try to re-connect to the WiFi network after it lost connection. #### 10.2.3) Install some __basic tools__ Install an __ftp server__ so that you can easily transfer files from the PC to the Raspi (login with user "pi" or set up a separate user if you want more security). Install wiringpi. ```` sudo apt-get -y install proftpd wiringpi ```` Install __node and npm__ Please note: Older Raspberry models and the Raspi Zero have an armv61 processor. In that case you should install directly from the "dist" directory of nodejs.org _the latest version published for the ARMv61 processor_: ```` curl -o node-v11.15.0-linux-armv6l.tar.gz https://nodejs.org/dist/v11.15.0/node-v11.15.0-linux-armv6l.tar.gz tar -xzf node-v11.15.0-linux-armv6l.tar.gz sudo cp -r node-v11.15.0-linux-armv6l/* /usr/local/ rm node-v11.15.0-linux-armv6l.tar.gz rm -fr node-v11.15.0-linux-armv6l ```` If you have a __newer model__ (check with ``cat /proc/cpuinfo``) you can use ``apt`` to get the latest version of nodejs and npm: ```` sudo apt-get install nodejs npm ```` #### 10.2.4) Install __berry-frame__ For the speaker modul we need a certain header file. We need some tools to play audio files. For i²c bus testing we should install i2c-tools. Allow _berries_ to shutdown the Raspi. ```` sudo apt-get -y install libasound2-dev alsa-tools bluealsa omxplayer mpg123 python-smbus i2c-tools sudo chmod +s /sbin/shutdown ```` Create you BERRY_HOME directory, e.g. ``/home/pi/berries``; enter the directory and call: ```` npm install berry-frame ```` * copy some binaries from ``node_modules/berry-frame/bin/`` to BERRY_HOME and make them executable. ```` cp node_modules/berry-frame/bin/berry . chmod +x berry cp node_modules/berry-frame/bin/onreboot . chmod +x onreboot cp node_modules/berry-frame/bin/monitor . chmod +x monitor ```` * call ```` ./berry ```` and __wait until the second part of the installation has completed__. This can take several minutes. When it shows a message telling something like "added 21 packages ..." everything has been installed; then use CTRL-C to terminate the process. * Call ``./berry`` again and you should only see the syntax help. * Look into ``onreboot``, adapt it to your neds and call "sudo crontab -e"; choose the "nano" editor and add the following line to the end of sudo´s crontab: ``@reboot /home/pi/berries/onreboot Hello`` Instead of ``Hello`` you should use the name of your own _berry_ once you created one. #### 10.2.5) Play with the _Hello berry_ * Now look for ``node_modules/berry-frame/sample_berries/Hello.zip`` and __unzip__ it into your BERRY_HOME directory so that you get a directory named ``Hello`` directly below BERRY_HOME. * Start the _Hello berry_ with logging activated: ``./berry Hello -l 1`` The server will start and your terminal will be blocked by the running process (unless you started it in the background as ``./berry Hello -l 1 &``). * Now open a browser on your PC at port 9001 (this is the port used for the ``Hello`` _berry_). ``http://my_raspberry_pi:9001 Instead of 'my_raspberry_pi' you must use the IP addresse or the symbolic network name of your Raspi. The terminal window in ``putty`` will show the traffic between the server and the web client. You can close the server by typing CTRL-C in the server window or by clicking on the red "x" in the web client user interface. ### 10.3) Google Application Credentials for Speech Synthesis The ``Speakers`` device has a method named ``say`` which uses the Google speech synthesis API to convert text into mp3 audio. Using the API requires a credential file which you must get from Google (register for API use, create a project, enable the TTS API, etc..). If you have that file, place it in BERRY_HOME and add as a first line into ``./berry``: ``set GOOGLE_APPLICATION_CREDENTIALS=path_to_your_credentials_file`` (on Windows) or ``export GOOGLE_APPLICATION_CREDENTIALS=path_to_your_credentials_file`` (on the Raspi). If you do not want to use the ``say`` method of ``Speakers`` there is no need to do anything. ### 10.4) I²C devices You can use ``i2cdetect -y 1`` and ``i2cget`` to check if your device is working before you control it via __berry-frame__. ### 10.5) Speakers Connecting a speaker via analogue cable is quite simple. ON the Rasp ZERO you could use a speaker HAT module (based on IS2 bus) or a USB audio dongle (which will probably require you to define ``devName:"hw:1,0"`` in the HWD. You might even be able to use a bluetooth connection, see here: https://www.raspberry-pi-geek.de/ausgaben/rpg/2018/04/musik-per-bluetooth-an-einen-lautsprecher-senden/ ## 11) SAMPLE BERRIES ### Hello The __Hello berry__ _lights a LED while a button is being held down._ This is the most basic _berry_ one can think of. That´s why it is called 'Hello (World)'. Play with it, adding more buttons and lights. ### Berry Shop More free sample _berries_ are offered for download at https://followthescore.org/berry _Berries_ from the shop can be installed vie ``berry -i name`` where _name_ is the name of the _berry_ you want to install. The installer will not overwrite a _berry_ which already exists in BERRY_HOME. ## 12) CREATING A BERRY We recommend to start working under __Windows__. Once your _berry_ runs in the emulation you transfer the files of your _berry_ to the Raspi and execute it there. ### 12.1) Decide on the hardware and the functionality of your _berry_ We want to have a push button and a LED. The LED shall be ON while the button is being held down. It shall be OFF while the button is UP. As this is the most basic application we can think of, let us call it "Hello". The name "Hello" is, precisely spoken, the name of a _Berry Type_. What does that mean? Well, you could have __two__ Raspberry computers with each one running your glorious "Hello" application. Then you have two INSTANCES of your APPLICATION TYPE. If you now have a web client which connects to both "Hello" _berries_ we would like to have a separate NAME for each INSTANCE. ``berry/bin/berry Hello -p 9001 -n World`` will create an instance of `Hello` named `World`. `berry/bin/berry Hello -p 9002 -n Moon` will create another instance of `Hello` named `Moon`. As we are running both instances of ``Hello`` on the same raspberry pi computer wen must assign different _names_ and _ports_ to them (see the ``-p`` cmdline option of ``berry``). ### 12.2) Describe your hardware configuration in a HWD file Create the new subdirectory ``Hello`` under your "berries" home directory. Create a HWD config file in ``Hello\server\Hello.hwd``. Decide on the default port number to use and put that number into the HWD at the ``port`` property. To make life easier for you we have already provided a file named Hello.hwd. Read that file carefully. Try to add another button and another LED! ### 12.3) Prepare the client Create ``Hello\audio`` and ``Hello\img``. Make a nice photo of your hardware or use a tool like "fritzing" to draw a schematic diagram and put it into ``Hello\img\Hello.jpg``. Note that the name of this image (without path) is referenced in the HWD file. ### 12.4) Develop your application logic In this simple exampe we do not need that because the HWD syntax allows us to link the LED directly to the action of the PUSH BUTTON. In a realistic application you will have to write your own code, of course. ### 12.5) Start your _berry_ on Windows Lean back and go to BERRY_HOME. Call ``berry/bin/berry Hello`` and wait what happens. If you do not see error messages complaininig about invalid JSON syntax in ``Hello.hwd`` you can now open a browser on the defined port like this: ``http://localhost:9001´´ ### 12.6) Improve your _berry_ Start the ``node_modules/berry-frame/bin/monitor.bat`` script in the background. Change the HWD or your JS application code. Then press the blue button in the client. The client will tell the server to terminate and restart. __Only after the restart__ the server will load your changed code and you see the effect. ### 12.7) Go to the target platform If everything runs fine in the emulation, copy your _berry_ into the BERRY_HOME directory on the Raspberry Pi (using ftp)) and test it there. Make sure the __monitor__ is running on the Raspberry Pi as well. (It may have been started already during the boot phase). If you make changes to the code or to the HWD file you can use the blue RESTART button in the Web UI to restart the server of your _berry_. If you keep your master version on Windows (which is good practice) you must make sure that all changed files are transferred to the Raspi before you execute your _berry_ there. Once everything seems ok you should also provide a ZIP file for your _berry_ so that interested users can download it and duplicate it onto their machines. Simply call ``berry -z myBerry``. This will create ``BERRY_HOME/zip/myBerry.zip``, the file which will be offered to the user in the web client for downloading a berry which is currently running. ## 13) LICENSE and COPYRIGHT Copyright 2019 Gero Scholz. Gero Scholz This program is free software; you can redistribute it and/or modify it under the terms of either: the ISC License. ## 14) SECURITY As mentioned above, __berry-frame__ does not come with any specific protections against malicious people or bots trying to attack your system. If you start the ``onreboot`` script from within ``crontab`` without ``runuser`` precautions it will run with root privileges (which seems to be technically necessary if you are using PWM but not for any other peripheral devices). If you did not change the password for user ``pi`` many people and bots will guess it easily. The command line option ``x`` allows to exclude certain UI options (comma separation): * rs = do not offer to restart the server process * rb = do not offer to reboot the raspi * U = do not offer to update the _berry-frame_ software * S = do not offer to stop the server process * X = do not offer to shutdown/halt the raspi * all = all of the above Please note that this is not a very tight protection as a manipulated client would be able to apply these commands to the server. Do not expose your Raspi to the internet unless you know what you are doing! If you really want to expose a _berry_ to the internet we recommend to install a reverse proxy which maps an arbitrary public URL(+port) to the (private) port where your _berry_is listening. In that case start your _berry_ with the commandline option "-f name_of_your_proxy" to ensure that it will only accept requests from your proxy. Typically the reverse proxy will also sit on the raspi and call the _berry_ via forwarding modules and URL rewriting. Let us assume you want to use port 80 of your reverse proxy for other purposes. So we choose a port, say 19009, as external port which interacts with port, say 9009, of your _berry_. Proceed as follows: * ``sudo apt-get install apache2`` * ``sudo a2enmod rewrite`` * ``sudo a2enmod proxy_http`` * ``sudo a2enmod proxy_fcgi`` * ``sudo a2enmod proxy_wstunnel`` * ``sudo a2enmod auth_digest`` * edit ``sudo nano /etc/apache2/ports.conf`` and add port 19009 * call ``sudo nano /etc/apache2/sites-available/myberry.proxy.conf``; if you like you can replace "myberry" by the name of your berry * The contents should look like this (optionally replacing "myberry" by the name of your berry)
Define BerryProxy myberry.proxy
<VirtualHost *:19009>
    ServerAdmin admin@${BerryProxy}
    ServerName ${BerryProxy}
    DocumentRoot /var/www/${BerryProxy}
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
    <Directory /var/www/${BerryProxy}/>
    </Directory>
</VirtualHost>
* Now create the root directory for the virtual host: ``/var/www/myberry.proxy`` and a small file within that directory, e.g. ``/var/www/myberry.proxy/hello.html`` * make sure that the root directory and all files inside belong to user www-data and to group www-data: ``sudo chown -R www-data:www-data /var/www/myberry.proxy`` * enable the virtual host: ``sudo a2ensite myberry.proxy.conf`` * restart apache: ``sudo systemctl reload apache2`` * Now open the __new port__ of your raspi in the browser and add the "hello.html" Example: .. Your raspi can be reached in the LAN via 192.168.0.88 or as 'my-raspi.fritz.box' .. So you call http://my-raspi.fritz.box:19009/hello.html .. Your berry uses port 9009. .. Your proxy is called "myberry.proxy" and exposes port 19009. .. In your router (Fritz box) you map 192.168.0.88:19009 to external port 20000 .. We assume that your router uses a dyn DNS service called dyndns.org and your account there assigns the subdomain 'lollipop' to you. In that case you can reach your _berry_ via http://lollipop.dyndns.org:20000/hello.html .. With a sophisticated reverse proxy configuration it might even be possible to use __https__ protocol in the web and map it to normal __http__ when talking to the _berry_. ------ * You should now see the contents of the file ``hello.html``. This means that the virtual host is working correctly at port 19009. * Now we can __add the proxy rules and the url rewriting rules__ to the config file. The complete file then looks like this:
Define BerryProxy myberry.proxy
<VirtualHost *:19009>
    ServerAdmin admin@${BerryProxy}
    ServerName ${BerryProxy}
    DocumentRoot /var/www/${BerryProxy}
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
    
    <Directory /var/www/${BerryProxy}/>
    </Directory>
    
    RewriteEngine On
    RewriteCond %{REQUEST_URI}  ^/socket.io            [NC]
    RewriteCond %{QUERY_STRING} transport=websocket    [NC]
    RewriteRule /(.*)           ws://localhost:9009/$1 [P,L]

    ProxyPass        /chat http://localhost:9009
    ProxyPassReverse /chat http://localhost:9009

    ProxyPass        /socket.io  http://localhost:9009/socket.io
    ProxyPassReverse /socket.io  http://localhost:9009/socket.io

    <Location />
        ProxyPass        http://127.0.0.1:9009/
        ProxyPassReverse http://127.0.0.1:9009/
    </Location>
</VirtualHost>
* start your berry so that it is listening at port 9009; use the cmdline option to restrict http request to those which have been forwarded by "myberry.proxy": ``./berry MyBerry -f myberry.proxy`` * you must also change your crontab entry and add ``-f myberry.proxy`` there, too. * restart apache: ``sudo systemctl reload apache2`` * call http://my-raspi.fritz.box:19009 from a DIFFERENT machine in the LAN or call http://lollipo.dyndns.org:20000 via a device outside of your LAN * You should see the user interface of your berry * if you call http://my-raspi.fritz.box:19009/hello.html you must get an error now, because the request is forwarded to your _berry_ regardless whether the file ``hello.html`` exists or not. You can now delete ``hello.html``. * if you try to call the port 9009 directly (from the LAN) it will respond with "forbidden", even when calling it from the raspi itself ----- * Now it is up to you to care for the security of the reverse proxy. Call ``sudo htdigest -c /var/www/.htpasswd -c Berry your_user_name`` and enter twice the password for that user. Make sure that the password file can be read by www-data: ``sudo chmod 644 /var/www/.htpasswd`` Then add the following lines to your vhost LOCATION definitions: ```` AuthType Digest AuthName "Berry" AuthUserFile /var/www/.htpasswd Require valid-user ```` The complete file now looks like this:
Define BerryProxy myberry.proxy
<VirtualHost *:19009>
    ServerAdmin admin@${BerryProxy}
    ServerName ${BerryProxy}
    DocumentRoot /var/www/${BerryProxy}
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
    
    <Directory /var/www/${BerryProxy}/>
    </Directory>
    
    RewriteEngine On
    RewriteCond %{REQUEST_URI}  ^/socket.io            [NC]
    RewriteCond %{QUERY_STRING} transport=websocket    [NC]
    RewriteRule /(.*)           ws://localhost:9009/$1 [P,L]

    ProxyPass        /chat http://localhost:9009
    ProxyPassReverse /chat http://localhost:9009

    ProxyPass        /socket.io  http://localhost:9009/socket.io
    ProxyPassReverse /socket.io  http://localhost:9009/socket.io

    <Location />
        ProxyPass        http://127.0.0.1:9009/
        ProxyPassReverse http://127.0.0.1:9009/
        AuthType Digest
        AuthName "Berry"
        AuthUserFile /var/www/.htpasswd
        Require valid-user
    </Location>
</VirtualHost>
When you now call the public address and the port which is mapped by the router (and forwarded by the reverse proxy) then a login window should require you to enter your credentials.