B4J Tutorial [ABMaterial]Raspberry Pi Switch LED

Sharing my experience in building my first ABMaterial WebApp running on a Raspberry Pi (RPi).
Note: any hints on improvements appreciated ;)

Objective

ABMaterial Learning Project: Web Application, running on a Raspberry Pi (RPi), to enable via browser, switching of an LED connected to a Raspberry Pi GPIO.

Step-by-Step Build
ABMaterial 2.00+ Library Files
Ensure the latest abmaterial.jar & xml plus other are copied from the ABM Archive Library folder to the B4J additional library folder. See here.

Project Folder
Create folder <path>\LEDSwitch.

Project Files
Copy folder \abmaterial\template to <path>\LEDSwitch
Rename template.b4j and meta to LEDSwitch.b4j and LEDSwitch.b4j.meta.

Open B4J Project
Open the B4J IDE with Project LEDSwitch.b4j.

Set Project Package name
In the B4J IDE, select Project > Build Configuration and set the Package Name: com.rpi.ledswitch.

Set Title and Description
In the Class ABMApplication, set the Title and Description, which are displayed in the Browser Tab.
Modify Sub BuildPage():
B4X:
public Sub BuildPage()
   AppPage.PageTitle = "RPi LED Switch"
   AppPage.PageDescription = "B4J HowTo Raspberry Pi LED switch using ABMaterial"

Set the name of the application - ensure set the right case!
In the Class ABMApplication set name and the initial page (which is created later stage)
B4X:
Sub Class_Globals
   Private AppName As String = "LEDSwitch"
   Private InitialPage As String = "LEDSwitchPage"

In the Class ABMPageTemplate set the AppName variable to LEDSwitch - with the same case as in ABMApplication!
B4X:
Sub Class_Globals  Public AppName As String = "LEDSwitch"

Create a New Page
Create a new Server WebSocket class named LEDSwitchPage.
Copy & paste all code from the class ABMTemplatePage into the new class LEDSwitchPage.
See LEDSwitchPage.bas.
Remove the ABMTemplatePage from the project, as not required anymore.

Set the Page Name
In the Class LEDSwitchPage set the Name of the page (same as the class name (case sensitive!).
B4X:
Sub Class_Globals  Public Name As String = "LEDSwitchPage"

Add the New Page to the App
In the class Main create an instance of your new page, initialize it and add it to the app.
The Sub AppStart in Main looks like:
B4X:
Sub AppStart (Args() As String)
   ABMShared.BuildTheme("mytheme")
   Dim myApp As ABMApplication
   myApp.Initialize
   Dim LEDSwitchP As LEDSwitchPage
   LEDSwitchP.Initialize
   myApp.AddPage(LEDSwitchP.Page)
   myApp.StartServer(srvr, "srvr", 51044)
   StartMessageLoop
End Sub

Compile and Run First Time
As this is first time, ABMaterial creates the required folders in the www folder, like
path\Objects\www\LEDSwitch\LEDSwitchPage

The B4J log example:
Collecting data from B4J source files... (1/2)
Analysing data from B4J source files... (2/2)
2016-10-17 14:23:31.665:INFO::main: Logging initialized @487ms
2016-10-17 14:23:31.775:INFO:eek:ejs.Server:main: jetty-9.3.z-SNAPSHOT
2016-10-17 14:23:31.850:INFO:eek:ejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@2a079c{/,file:///C:/Daten/b4/b4j/b4jhowto/B4JHowToABMRPiGPIO/Objects/www/,AVAILABLE}
2016-10-17 14:23:31.853:INFO:eek:ejs.AbstractNCSARequestLog:main: Opened C:\Daten\b4\b4j\b4jhowto\B4JHowToABMRPiGPIO\Objects\logs\b4j-2016_10_17.request.log
2016-10-17 14:23:32.006:INFO:eek:ejs.ServerConnector:main: Started ServerConnector@1993335{HTTP/1.1,[http/1.1]}{0.0.0.0:51042}
2016-10-17 14:23:32.007:INFO:eek:ejs.Server:main: Started @830ms

Open a Browser and enter localhost:51044/LEDSwitch/.
This will load the pages located in LEDSwitch\LEDSwitchPage. The Browser URL is updated to localhost:51044/LEDSwitch/LEDSwitchPage.

Themes
In the class ABMShared the themes used for this app are defined.
Note: If a Page specific Themes are needed, then create those in the Sub BuildTheme in the page (like for the class LEDSwitchPage).
Sub BuildTheme(themeName As String)
MyTheme.Initialize(themeName)
MyTheme.Page.BackColor = ABM.COLOR_TEAL
MyTheme.Page.BackColorIntensity = ABM.INTENSITY_LIGHTEN5
MyTheme.AddRowTheme("headertheme")
MyTheme.Row("headertheme").BackColor = ABM.COLOR_TEAL
MyTheme.Row("headertheme").BackColorIntensity = ABM.INTENSITY_DARKEN1
MyTheme.AddContainerTheme("footertheme")
MyTheme.Container("footertheme").BackColor = ABM.COLOR_TEAL
MyTheme.Container("footertheme").BackColorIntensity = ABM.INTENSITY_LIGHTEN2
MyTheme.AddLabelTheme("whitefc")
MyTheme.Label("whitefc").ForeColor = ABM.COLOR_WHITE
MyTheme.AddLabelTheme("justify")
MyTheme.Label("justify").align = ABM.TEXTALIGN_JUSTIFY
MyTheme.AddLabelTheme("lightblue")
MyTheme.Label("lightblue").ForeColor = ABM.COLOR_LIGHTBLUE
MyTheme.Label("lightblue").ForeColorIntensity = ABM.INTENSITY_DARKEN2
MyTheme.AddLabelTheme("bluefc")
MyTheme.Label("bluefc").ForeColor = ABM.COLOR_BLUE
MyTheme.AddLabelTheme("redfc")
MyTheme.Label("redfc").ForeColor = ABM.COLOR_BLUE
MyTheme.AddButtonTheme("buttonon")
MyTheme.Button("buttonon").ForeColor = ABM.COLOR_WHITE
MyTheme.Button("buttonon").BackColor = ABM.COLOR_GREEN
MyTheme.AddButtonTheme("buttonoff")
MyTheme.Button("buttonoff").ForeColor = ABM.COLOR_WHITE
MyTheme.Button("buttonoff").BackColor = ABM.COLOR_RED
MyTheme.AddToastTheme("toasttheme")
MyTheme.Toast("toasttheme").ForeColor = ABM.COLOR_WHITE
MyTheme.Button("buttonoff").BackColor = ABM.COLOR_BLUE
MyTheme.Toast("toasttheme").Rounded = True
MyTheme.AddSwitchTheme("switchtheme")
MyTheme.Switch("switchtheme").SwitchOnColor = ABM.COLOR_GREEN
MyTheme.Switch("switchtheme").SwitchOnColorIntensity = ABM.INTENSITY_DARKEN4
MyTheme.Switch("switchtheme").SwitchOffColor = ABM.COLOR_RED
MyTheme.Switch("switchtheme").SwitchOffColorIntensity = ABM.INTENSITY_DARKEN4
MyTheme.Switch("switchtheme").LabelColor = ABM.COLOR_BLACK
MyTheme.Switch("switchtheme").LabelColor = ABM.INTENSITY_DARKEN4
MyTheme.Switch("switchtheme").LabelFontSize = "28px"
MyTheme.Switch("switchtheme").Colorize(ABM.COLOR_TEAL)
End Sub

Create a Fixed Footer
In the class ABMShared add a BuildFooterFixed.
Public Sub BuildFooterFixed(page As ABMPage)
page.isFixedFooter= True
page.PaddingBottom = 150
' Add a new row
page.Footer.AddRows(1, True, "").AddCellsOS(2,0,0,0,6,6,6, "")
' Build the grid
page.Footer.BuildGrid
page.Footer.UseTheme("footertheme")

' Add a label to Row 1, Cell 1
Dim lbl1 As ABMLabel
lbl1.Initialize(page, "footlbl1", $"B4J HowTo by {AL}http://www.rwblinn.de{AT}rwblinn.de{/AL}{BR}{BR}${Main.Version}"$,ABM.SIZE_PARAGRAPH, False, "whitefc")
page.Footer.Cell(1,1).AddComponent(lbl1)

' Add a label to Row 1, Cell 1
Dim lbl2 As ABMLabel
lbl2.Initialize(page, "footlbl2", "ABMaterial by {AL}http://alwaysbusycorner.com/abmaterial{AT}Alain Bailleul{/AL}{BR}{BR}B4J by {AL}http://www.bx4.com{AT}Anywhere Software{/AL}",ABM.SIZE_PARAGRAPH, False, "whitefc")
page.Footer.Cell(1,2).AddComponent(lbl2)
End Sub

Next Steps
The webapp initial framework has been created. Now its time to design & build the application as such:
  • Define & build a shared code class for the GPIO Controller
  • Design the Page Grid and its components
  • Define & build the LED control logic
Define the Shared Code Class for the GPIO Controller
The GPIO Controller requires the jPi4J Library (read here).
This class defines Init the GPIO Controller, set the GPIO Pin to digital output, switch the pin state to high (true) or low (false), get pin state.
See LEDController.bas.

Design the Page Grid (see also screenshot below)
In the Class LEDSwitchPage, define the page and its components in the Sub BuildPage().
There are 4 rows with cells and its ABM Controls:
  • Row 1, 1 cell: Header (ABMLabel)
  • Row 2, 3 cells: 1=Switch (ABMSwitch), 2=Switched info (ABMLabel), 3=Not Used
  • Row 3, 1 cell: Empty
  • Row 4, 1 cell: Divider (ABMDivider)
  • Row 5, 1 cells: Info (ABMCard)
IMPORTANT = EACH CONTROL MUST HAVE AN UNIQUE ID.
See LEDSwitchPage.bas.

Define LED Control Logic
The event Sub SwitchLED3_Clicked handles switching and information updates via the Webpage triggered by the User.
B4X:
Sub SwitchLED3_Clicked(Target As String)
  Dim LEDSwitch As ABMSwitch = page.Component("SwitchLED3")
  Log($"LED Switch clicked to ${LEDSwitch.state}"$)
  ' Set the LED Pin state
  LEDController.SetPinState(LEDController.Pin3, LEDSwitch.state)
...

In Sub Page_Ready(), the state of the LEDSwitch is set according the pin GPIO state:
B4X:
Dim LEDSwitch As ABMSwitch = page.Component("SwitchLED3")
LEDSwitch.State = LEDController.GetPinState(LEDController.Pin3)
See LEDSwitchPage.bas.

In the Class Main, Sub AppStart the GPIOController is initialized prior executing the ABM Subs to build & start the application.
B4X:
Sub AppStart (Args() As String)
   ' Init the GPIO controller prior building the pages as the state of the pin is used by the abmswitch
   LEDController.Init_GPIOController
   ' Set the Pin Number 3 = physical pin 15 = GPIO22 = GPIO_GEN3 as GpioPinDigitalOutput
   ' (the GPIO_GEN3 indicates Pin 3)
   LEDController.Init_GPIOPinDigitalOutput(LEDController.Pin3,3,False)

   ' ABM
   ABMShared.BuildTheme("mytheme")
   Dim myApp As ABMApplication
   myApp.Initialize
   Dim LEDSwitchP As LEDSwitchPage
   LEDSwitchP.Initialize
   myApp.AddPage(LEDSwitchP.Page)
   myApp.StartServer(srvr, "srvr", 51044)
   StartMessageLoop
End Sub
See LEDSwitch.b4j.

RPi B4J Bridge
During development, the B4J-Bridge running on the Raspberry Pi has been used.
The project www folder must be copied to the Raspberry Pi tempjars folder, e.g. /home/pi/b4j/tempjars/www/LEDSwitch/LEDSwitchPage.
Copy the files, after the previous described step "Compile and Run first time".
When compiling and run, wait till the server is running (this might take a few seconds depending Network & RPi performance). Watch the B4J IDE log:
2016-11-30 14:16:45.155:INFO::main: Logging initialized @2631ms
2016-11-30 14:16:45.741:INFO:eek:ejs.Server:main: jetty-9.3.z-SNAPSHOT
2016-11-30 14:16:46.212:INFO:eek:ejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@1e2dbf3{/,file:///home/pi/b4j/tempjars/www/,AVAILABLE}
2016-11-30 14:16:46.227:INFO:eek:ejs.AbstractNCSARequestLog:main: Opened /home/pi/b4j/tempjars/logs/b4j-2016_11_30.request.log
2016-11-30 14:16:46.312:INFO:eek:ejs.ServerConnector:main: Started ServerConnector@2a67b4{HTTP/1.1,[http/1.1]}{0.0.0.0:51044}
2016-11-30 14:16:46.317:INFO:eek:ejs.Server:main: Started @3803ms
WebSocket Connected
Waiting for value (11 ms)
LEDControlPage ready!
Waiting for value (14 ms)

RPi Application Folder
Create a folder /home/pi/b4j/ledswitch and copy the files from the project\objects folder. The RPi folder looks like:
/home/pi/b4j/ledswitch/BaseDefaults.def
/home/pi/b4j/ledswitch/BaseTranslations.lng
/home/pi/b4j/ledswitch/copymewithjar.needs
/home/pi/b4j/ledswitch/LEDSwitch.jar
/home/pi/b4j/ledswitch/www

Start the App
Start the app (as sudo!) from a terminal, e.g.
pi@33:~ $ cd b4j/ledswitch
pi@33:~/b4j/ledswitch $ sudo java -jar LEDSwitch.jar
2016-11-30 17:38:42.412:INFO::main: Logging initialized @2697ms
2016-11-30 17:38:43.015:INFO:eek:ejs.Server:main: jetty-9.3.z-SNAPSHOT
2016-11-30 17:38:43.490:INFO:eek:ejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@1e2dbf3{/,file:///home/pi/b4j/tempjars/www/,AVAILABLE}
2016-11-30 17:38:43.504:INFO:eek:ejs.AbstractNCSARequestLog:main: Opened /home/pi/b4j/tempjars/logs/b4j-2016_11_30.request.log
2016-11-30 17:38:43.592:INFO:eek:ejs.ServerConnector:main: Started ServerConnector@2a67b4{HTTP/1.1,[http/1.1]}{0.0.0.0:51044}
2016-11-30 17:38:43.597:INFO:eek:ejs.Server:main: Started @3892ms
Connected
Waiting for value (18 ms)
ready!
Disconnected
WebSocket Connected
Waiting for value (15 ms)
LEDControlPage ready!
Waiting for value (11 ms)
LED Switch clicked to true
Waiting for value (11 ms)
LED Switch clicked to false
WebSocket Disconnected

Download Source here.

Screenshot Browser
upload_2016-11-30_17-58-22.png


Enjoy!
 
Last edited:

Harris

Expert
Licensed User
Longtime User
Step-by-Step Build
ABMaterial 2.00+ Library Files
Ensure the latest abmaterial.jar & xml plus other are copied from the ABM Archive Library folder to the B4J additional library folder. See here.


I think he did...
 

Gary Miyakawa

Active Member
Licensed User
Longtime User
This is my first attempt with ABMaterial so I'm not certain I've got it completely installed correctly.

I'm pretty sure it's something I'm doing wrong but after running the application (downloading the .zip) and installing... All I'm getting is 3 rings spinning in the middle of the screen.

Is that something missing from my ABMaterial Install or ???

Also, there appears to have been a change in the AppPage.InitializeWithTheme command. It now requires another field (SessionMaxInactiveIntervalSeconds) so I added it as a 10.

Any suggestions would be greatly appreciated!

Cheers,

Gary Miyakawa
 

rwblinn

Well-Known Member
Licensed User
Longtime User
Hi,

thanks for bringing up - verified installation against ABMaterial 3.03. Beside the changes required for
  • SessionMaxInactiveIntervalSeconds - set to 10
  • Raspberry Pi 3 installing the latest version of wiringPi (2.44) and Pi4J 1.2 snapshot - to be able to use the BCM2835 Hardware
the app is running fine (note: changed port to 51042 as using as default in my browser).
  • Is the ABMaterial 3.03 www folder copied to the project folder and also on the Raspberry Pi?
  • What output is given when starting the jar?
Example Output when starting the jar and switching the LED few times after connecting http://192.168.0.8:51042/LEDSwitch
B4X:
pi@raspberrypi:~/b4j/ledswitch $ sudo java -jar LEDSwitch.jar
Building core.min.css...
2017-05-06 10:40:27.809:INFO::main: Logging initialized @1763ms
2017-05-06 10:40:28.160:INFO:oejs.Server:main: jetty-9.3.z-SNAPSHOT
2017-05-06 10:40:28.457:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@1205a84{/,file:///home/pi/b4j/ledswitch/www/,AVAILABLE}
2017-05-06 10:40:28.464:INFO:oejs.AbstractNCSARequestLog:main: Opened /home/pi/b4j/ledswitch/logs/b4j-2017_05_06.request.log
2017-05-06 10:40:28.514:INFO:oejs.ServerConnector:main: Started ServerConnector@11f0959{HTTP/1.1,[http/1.1]}{0.0.0.0:51042}
2017-05-06 10:40:28.516:INFO:oejs.Server:main: Started @2475ms
WebSocket Connected
Waiting for value (8 ms)
LED Switch clicked to true
Waiting for value (10 ms)
Waiting for value (8 ms)
LED Switch clicked to false
Waiting for value (6 ms)
Waiting for value (7 ms)
upload_2017-5-6_10-53-34.png
 

Gary Miyakawa

Active Member
Licensed User
Longtime User
I see the www directory on both the Project and in the RPI. They appear to be the same.

I appear to get all the messages you get up to the WebSocket Connected (which, never appears)...

Here is what I get:
2017-05-06 22:00:18.897:INFO::main: Logging initialized @1784ms
2017-05-06 22:00:19.281:INFO:eek:ejs.Server:main: jetty-9.3.z-SNAPSHOT
2017-05-06 22:00:19.617:INFO:eek:ejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@1907bac{/,file:///home/pi/tempjars/www/,AVAILABLE}
2017-05-06 22:00:19.626:INFO:eek:ejs.AbstractNCSARequestLog:main: Opened /home/pi/tempjars/logs/b4j-2017_05_07.request.log
2017-05-06 22:00:19.709:INFO:eek:ejs.ServerConnector:main: Started ServerConnector@199d22e{HTTP/1.1,[http/1.1]}{0.0.0.0:51044}
2017-05-06 22:00:19.711:INFO:eek:ejs.Server:main: Started @2612ms

I'm missing something, obviously....

Thanks for the help!

Gary Miyakawa
 

rwblinn

Well-Known Member
Licensed User
Longtime User
Seems a communication issue.

Can you run the ABMaterial Demo from the Raspberry Pi?
 

Cableguy

Expert
Licensed User
Longtime User
in the RPI side, as it is acting like the server, both TCP and UDP must be allowed for the sockets to function...
At least, on my vps is what I had to do! (Firewall)
 

Gary Miyakawa

Active Member
Licensed User
Longtime User
When I go to load the abmaterial demo, I get "missing parameter" errors around the page.cell(2,1).setfixedheight(800). I've added "True" there to meet parameter requirements.

As clearly stated in the documentation, I had not moved the www (js, css, etc) files to the output area on the RPi. Once I moved those, all works as designed.

Thanks for the help everyone !

Gary Miyakawa
 
Top