Advance example

This is a example project how to use Steelsquid Kiss OS to control a 10 LED bar, two buttons and the built in WEB-server...
If you do this you have learn a lot how to work with Steelsquid Kiss OS.
This is what i want to manage.
  • Press the upper button to light one more LED until all lights.
  • Press the lower button to decrease the number of glowing LEDs.
  • The bottom LED should never be extinguished when you push down button.
  • I also want a simple WEB interface that also can control the LED bar in the same way.
  • And finally all LEDs should illuminate on network connected.
  • And no LED lit on network disconnect.
  • Flash all LEDs when there is a file in the /root directory named flash.
    And then delete that file.
  • Remember number of lit LEDs from last time
  • And a parameter that say if Steelsquid Kiss OS is to enable all this

Dependencies on your development computer

For the synchronization scriptSSH and GIT to works on Linux (preferably Debian) you need this packages installed.
It should work on any other Linux distribution also.
It probably works on Mac OS X also.
  • gzip
  • git
  • openssh-client
  • python2.7
  • paramiko
apt-get install bash gzip git openssh-client python2.7 python-paramiko

Windows
Use Putty for SSH: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
GIThttps://git-scm.com/download/win
You do not need GIT, you can just download a zip instead if you want...
For synchronization use the EXE-file:  steelsquid_synchronize.exe

Install Steelsquid KISS OS on the Raspberry PI

Change directory to the project home on your development computer
  • Insert sd-card into the Raspberry Pi and power it on
    The IP of the Raspberry PI will be printed on the screen

Get the source code

On your development computer.
Change directory to where you want the source code (a project folder will be created)
git clone https://github.com/steelsquid/steelsquid-kiss-os.git
You can also download a zip here: Download this zip file and extract

Start the synchronisation between Raspberry and development computer

Go the the ROOT where you downloaded the source and edit config.txt
Should look like this, except the IP number that you must change to your Raspberry Pi IP. (For more info see this)
192.168.0.194
22
root
raspberry

Then execute: ./steelsquid_synchronize.py
Windows users: steelsquid_synchronize.exe
All files will now sync to the Raspberry Pi.
For more info on the synchronize program see: Extend functionality of Steelsquid Kiss OS

I also recommend changing the development mode.
In the synchronization program window execute: steelsquid dev-on
It should look like this:
 # steelsquid dev-on
 2015-12-17 21:22:52 Command executed OK

Connect LED and buttons to Raspberry Pi

Connect all the LED cathode to the GND on the Raspberry.
Also connect the buttons to GND.
 Raspberry  Button/LED
 GND  Button up
 GND  Button down
 GND  All LED cathode
 GPIO15  Button up
 GPIO14  Button down
 GPIO25  LED 10 (top)
 GPIO24  LED 9
 GPIO23  LED 8
 GPIO18  LED 7
 GPIO04  LED 6
 GPIO17  LED 5
 GPIO27  LED 4
 GPIO22  LED 3
 GPIO10  LED 2
 GPIO09  LED 1 (bottom)


The module containing all logic

You can add all logic to kiss_expand.py directly but i recommend that you create a new file.
In the synchronization program window press N then enter the name of the module.
Use the name: led_bar
 # n
Enter name of module to create: led_bar
2015-12-18 12:39:09 Creating new module led_bar.py in modules/
Restart the steelsquid service for this to take effect (type A and enter)

#
2015-12-18 12:39:10 SYNC: modules/led_bar.py

Now there is a file under modules/ named led_bar.py, it is a copy of kiss_expand.py.
Open the file in you favorite editor .
I will now add all that is needed in this new file, or you can just copy the entire file at once.
I think the comments in the code says it all...
The finish file: led_bar.py
  • Import module
    In the top of the file where the import is add: import os
  • Remove unused stuff
    Search for class SOCKET(object) and class PIIO(object)
    You can remove both those classes and the content of them
  • The enable and disable methods
    I do not use this in the example but can be useful if you want to do some thing when this module is enabled or disabled. Maybe you want to create a file och enable other modules...
    # Is this module started
    # This is set by the system automatically.
    is_started = False
            
    def on_start():
        '''
        When this module is enabled what needs to be done (execute: steelsquid module XXX on)
        Maybe you need create some files or enable other stuff.
        '''
        pass 
            
    
    def on_stop():
        '''
        When this module is disabled what needs to be done (execute: steelsquid module XXX off)
        Maybe you need remove some files or disable other stuff.
        '''
        pass     
  • The SYSTEM class
    Make the SYSTEM class look like this.
    class SYSTEM(object):
        '''
        Methods in this class will be executed by the system if module is enabled
        on_start() exist it will be executed when system starts (boot)
        on_stop() exist it will be executed when system stops (shutdown)
        on_network(status, wired, wifi_ssid, wifi, wan) exist it will be execute on network up or down
        on_vpn(status, name, ip) This will fire when a VPN connection is enabled/disabled.
        on_bluetooth(status) exist it will be execute on bluetooth enabled
        on_mount(type_of_mount, remote, local) This will fire when USB, Samba(windows share) or SSH is mounted.
        on_umount(type_of_mount, remote, local) This will fire when USB, Samba(windows share) or SSH is unmounted.
        on_event_data(key, value) exist it will execute when data is changed with steelsquid_kiss_global.set_event_data(key, value)
        '''
        
        # I do not want the ledbars to change on the first network event, or the saved value from disk will 
        # have no purpuse
        first_network_change = True
            
        @staticmethod
        def on_start():
            '''
            This will execute when system starts
            Do not execute long running stuff here, do it in on_loop...
            '''
            steelsquid_utils.shout("The LED bar is enabled")
    
            # Read number of lit LEDs from disk, if not found on the disk use 5
            led_bars_lit = int(steelsquid_utils.get_parameter("led_bars_lit", "5"))
    
            # USING global for the logic to lit the led-bar
            GLOBAL.led_bars_lit(led_bars_lit)
    
            # Listen for click on button s
            # When GPIO state change from hight>low>hight fire a method
            # The button is connected to GND (when button is clicked gpio is LOW) that 
            # why i use resistor=PULL_UP
            steelsquid_pi.gpio_click(15, SYSTEM.on_button_increase, resistor=steelsquid_pi.PULL_UP) # Listen 
            steelsquid_pi.gpio_click(14, SYSTEM.on_button_decrease, resistor=steelsquid_pi.PULL_UP) # Listen 
            
    
        @staticmethod
        def on_stop():
            '''
            This will execute when system stops
            Do not execute long running stuff here
            '''
            steelsquid_utils.shout("The LED bar disabled")
    
            # Turn of all led
            GLOBAL.led_bars_lit(0, save_to_disk=False)
    
            # Stop listen for click on buttons
            steelsquid_pi.gpio_event_remove(15)
            steelsquid_pi.gpio_event_remove(14)        
            
            
        @staticmethod
        def on_loop():
            '''
            This will execute over and over again untill it return None or -1
            If it return a number larger than 0 it will sleep for that number of seconds before execute again.
            If it return 0 it will not not sleep, will execute again immediately.
            ''' 
            # Is there a file in the /root directory named flash
            if os.path.isfile("/root/flash"):
                # Remove the file
                os.remove('/root/flash')
                # Lit all the LEDs
                GLOBAL.led_bars_lit(10, save_to_disk=False, save_number_led_bars_lit=False)
                # Afer a second show the old number of leds
                steelsquid_utils.execute_delay(1, GLOBAL.led_bars_lit, (None,))
            # Will sleep for half a seconds before execute again
            return 0.5
    
    
        @staticmethod
        def on_network(status, wired, wifi_ssid, wifi, wan):
            '''
            Execute on network up or down.
            status = True/False (up or down)
            wired = Wired ip number
            wifi_ssid = Cnnected to this wifi
            wifi = Wifi ip number
            wan = Ip on the internet
            '''    
            # I do not want the ledbars to change on the first network event, or the saved value from disk will
            # have no purpuse
            if SYSTEM.first_network_change:
                SYSTEM.first_network_change=False
            else:
                # If network is up lit all led and if network is down lit no led
                if status==True:
                    GLOBAL.led_bars_lit(10)
                else:
                    GLOBAL.led_bars_lit(0)
    
    
    
        @staticmethod
        def on_button_increase(gpio):
            '''
            Fire when the up button is clicked
            @param gpio: The gpio 
            '''
            steelsquid_utils.shout_time("Button increase clicked")
            # USING global for the logic to lit the led-bar
            GLOBAL.led_bars_increase()
            
    
        @staticmethod
        def on_button_decrease(gpio):
            '''
            Fire when the down button is clicked
            @param gpio: The gpio 
            '''
            steelsquid_utils.shout_time("Button decrease clicked")
            # USING global for the logic to lit the led-bar
            GLOBAL.led_bars_decrease()

  • The LOOP class
    The loop class shall look like this.
    class LOOP(object):
        '''
        Every static method with no inparameters will execute over and over again untill it return None or -1
        If it return a number larger than 0 it will sleep for that number of seconds before execute again.
        If it return 0 it will not not sleep, will execute again immediately.
        Every method will execute in its own thread
        '''
    
            
        @staticmethod
        def on_loop():
            '''
            This will execute over and over again untill it return None or -1
            If it return a number larger than 0 it will sleep for that number of seconds before execute again.
            If it return 0 it will not not sleep, will execute again immediately.
            ''' 
            # Is there a file in the /root directory named flash
            if os.path.isfile("/root/flash"):
                # Remove the file
                os.remove('/root/flash')
                # Lit all the LEDs
                GLOBAL.led_bars_lit(10, save_to_disk=False, save_number_led_bars_lit=False)
                # Afer a second show the old number of leds
                steelsquid_utils.execute_delay(1, GLOBAL.led_bars_lit, (None,))
            # Will sleep for half a seconds before execute again
            return 0.5
  • The WEB class
    Make the WEB class look like this.
    class WEB(object):
        '''
        Methods in this class will be executed by the webserver if activate() return True and the webserver 
        is enabled
        If is a GET it will return files and if it is a POST it executed commands.
        It is meant to be used as follows.
        1. Make a call from the browser (GET) and a html page is returned back.
        2. This html page then make AJAX (POST) call to the server to retrieve or update data.
        3. The data sent to and from the server can just be a simple list of strings.
        For more examples how it work:
         - steelsquid_http_server.py
         - steelsquid_kiss_http_server.py
         - web/index.html
        '''
    
        @staticmethod
        def ledbar_get(session_id, parameters):
            '''
            This is a request from the web page led_bar.html
            Get status of lit LED (how many is lit)
            @param session_id: A session id
            @param parameters: Paramaters from the web page request 
                               (a list of paramaters)
            '''
            # Return number of lit to the web page
            return [GLOBAL.number_led_bars_lit]
    
    
        @staticmethod
        def ledbar_set(session_id, parameters):
            '''
            This is a request from the web page led_bar.html
            Set status of lit LED (how many should be lit)
            @param session_id: A session id
            @param parameters: Paramaters from the web page request 
                               (a list of paramaters)
            
            '''
            # Get number fron the webpage request
            number = int(parameters[0])
            
            # Check if walue is OK
            if number < 1 or number > 10:
                # This text will show in a popup on the web page
                raise Exception("Value must be between 1 and 10!")
            
            # Set the number of lit LEDs
            GLOBAL.led_bars_lit(number)
            
            # Return number of lit to the web page
            return [GLOBAL.number_led_bars_lit]
    
    
        @staticmethod
        def ledbar_increase(session_id, parameters):
            '''
            This is a request from the web page led_bar.html
            Increase number of lit LED
            @param session_id: A session id
            @param parameters: Paramaters from the web page request 
                               (a list of paramaters)
            '''
            # Increase the number of lit LEDs
            GLOBAL.led_bars_increase()
            
            # Return number of lit to the web page
            return [GLOBAL.number_led_bars_lit]
    
    
        @staticmethod
        def ledbar_decrease(session_id, parameters):
            '''
            This is a request from the web page led_bar.html
            Decrease number of lit LED
            @param session_id: A session id
            @param parameters: Paramaters from the web page request 
                               (a list of paramaters)
            '''
            # Decrease the number of lit LEDs
            GLOBAL.led_bars_decrease()
            
            # Return number of lit to the web page
            return [GLOBAL.number_led_bars_lit]
  • The EVENTS class
    I do not use any events in this example, so you can leave it blank or remove it...
    class EVENTS(object):
        '''
        Create staticmethods in this class to listen for asynchronous events.
        Example: If you have a method like this:
          @staticmethod
          def this_is_a_event(a_parameter, another_parameter):
             print a_parameter+":"+another_parameter
        Then if a thread somewhere in the system execute this: 
        steelsquid_kiss_global.broadcast_event("this_is_a_event", ("para1", "para2",))
        The method def this_is_a_event will execute asynchronous
        '''
  • The GLOBAL class
    Make the GLOBAL class look like this.
    class GLOBAL(object):
        '''
        Put global staticmethods in this class, methods you use from different part of the system.
        Maybe the same methods is used from the WEB, SOCKET or other part, then put that method her.
        It is not necessary to put it her, you can also put it direcly in the module (but i think it is 
        kind of nice to have it inside this class)
        '''
        
        # Map number of led to gpio
        GPIO_MAPING = [9, 10, 22, 27, 17, 4, 18, 23, 24, 25]
    
        # How many LEDs is lit now
        number_led_bars_lit=0
    
        @staticmethod
        def led_bars_lit(nr_led_bars_lit=None, save_to_disk=True, save_number_led_bars_lit=True):
            '''
            Lit number of LED that should be lit.
            '''
            steelsquid_utils.debug("led_bars_lit")
            # Should i change the GLOBAL.number_led_bars_lit
            if nr_led_bars_lit!=None and save_number_led_bars_lit:
                GLOBAL.number_led_bars_lit = int(nr_led_bars_lit)
            # What should i use when iterting the leds
            if nr_led_bars_lit !=None and not save_number_led_bars_lit:
                iterate_on_this = nr_led_bars_lit
            else:
                iterate_on_this = GLOBAL.number_led_bars_lit
            # Set GPIO hight or low depending on how many led i want to lit
            for i in range(0, 10):
                if i < iterate_on_this:
                    steelsquid_pi.gpio_set(GLOBAL.GPIO_MAPING[i], True)
                else:
                    steelsquid_pi.gpio_set(GLOBAL.GPIO_MAPING[i], False)
            # Save value to disk
            if save_to_disk:
                steelsquid_utils.set_parameter("led_bars_lit", GLOBAL.number_led_bars_lit)
            steelsquid_utils.shout_time("Number of LED glowing: " + str(GLOBAL.number_led_bars_lit))
    
    
        @staticmethod
        def led_bars_increase():
            '''
            Will light one more LED.
            '''
            steelsquid_utils.debug("led_bar_increase")
            if GLOBAL.number_led_bars_lit < 10:
                GLOBAL.number_led_bars_lit = GLOBAL.number_led_bars_lit + 1
            GLOBAL.led_bars_lit()
    
    
        @staticmethod
        def led_bars_decrease():
            '''
            Will light one less LED.
            '''
            steelsquid_utils.debug("led_bar_decrease")
            if GLOBAL.number_led_bars_lit > 1:
                GLOBAL.number_led_bars_lit = GLOBAL.number_led_bars_lit - 1
            GLOBAL.led_bars_lit()
    

Activate the module

For the module to start on boot you need to activate it.
Do that by E in the synchronization program and select the module (led_bar)
 # e
   STATUS     MODULE NAME
-----------------------------------------------
1 [Enabled]  led_bar
2 [Disabled] steelsquid_kiss_alarm
3 [Disabled] steelsquid_kiss_expand
4 [
Disabled]  steelsquid_kiss_piio
5 [Disabled] steelsquid_kiss_rover
Enter number of the module to enable (1, 2, 3...): 1
2016-01-02 14:36:14 Request enable of module: kiss_piio

#
The steelsquid service will restart....
If you press L you will see that the module enabled:
 # l
STATUS     MODULE NAME
-----------------------------------------------
[Enabled]  led_bar
[Disabled] steelsquid_kiss_alarm
[Disabled] steelsquid_kiss_expand
[
Disabled]  steelsquid_kiss_piio
[Disabled] steelsquid_kiss_rover

The HTML interface

You can use the file web/expand.html directly or create a new. In this example we create a new.
In the synchronization program window press W then enter the name of the html file.
You can use any name you want, but in this example i use the same as the module.
Use the name: led_bar
 # w
Enter name of html file to create: led_bar
2015-12-18 12:40:05 Creating new html file led_bar.html in web/

#
2015-12-18 12:40:06 SYNC: web/led_bar.html

Now there is a file under web/ named led_bar.py, it is a copy of template.html.
Open the file in you favorite editor and add make it look like this (just copy and past all):
I think it is pretty easy to understand if you know HTML...
The raw file: led_bar.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
    <head>
        <title>LCD BAR test</title>
        <meta http-equiv="Content-Language" content="en" />
        <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
        <meta name="LED bar" content="Example how to use Steelsquid KISS OS" />
        <meta name="keywords" content="led, example" />
        <meta name="author" content="Andreas Nilsson (Steelsquid)" />
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
        <link rel="icon" href="favicon.ico" type="image/x-icon"/>
        <link rel="shortcut icon" href="favicon.ico" type="image/x-icon"/>
        <link rel="stylesheet" type="text/css" href="steelsquid.css"/>
        <script type="text/javascript" src="jquery.js"></script>
        <script type="text/javascript" src="steelsquid.js"></script>     
        <script type="text/javascript">
            //<![CDATA[ 
            
            /**
             * This will execute when the page is loaded
             */
            function onPageLoad(){
                //Get the number of lit LED on page load
                submitNoPW('ledbar_get');
            }
            
            /**
             * This will execute every 1 second
             */
            function onEvery01s(){
                //Get the number of lit LED every 1 second
                submitNoPW('ledbar_get');
            }
            
            /**
             * This is the answer from the server for the request ledbar_get (submitNoPW('ledbar_get'))
             * The answer is the list returned from the function with the same name in led_bar.py
             */
            function on_ledbar_get(paramaters){
                number = paramaters[0];
                setContent("number_of_led", number);
            }

            /**
             * This is the answer from the server for the request ledbar_set
             * The answer is the list returned from the function with the same name in led_bar.py
             */
            function on_ledbar_set(paramaters){
                //The answer is the same as request ledbar_get
                on_ledbar_get(paramaters);
            }

            /**
             * This is the answer from the server for the request ledbar_increase
             * The answer is the list returned from the function with the same name in 
             * steelsquid_kiss_http_expand.py
             */
            function on_ledbar_increase(paramaters){
                //The answer is the same as request ledbar_get
                on_ledbar_get(paramaters);
            }

            /**
             * This is the answer from the server for the request ledbar_decrease
             * The answer is the list returned from the function with the same name in 
             * steelsquid_kiss_http_expand.py
             */
            function on_ledbar_decrease(paramaters){
                //The answer is the same as request ledbar_get
                on_ledbar_get(paramaters);
            }
            
            //]]>
        </script>
        
    </head>
    <body>
        <h1>The LED Bar web interface</h1>
        <div><br/></div>
        <div>This is the number of lit LEDs, updated every 1 seconds.</div>
        <table class="keyvalue">
            <tbody>
                <tr>
                    <td>
                        Number of LED lit:
                    </td>
                    <td id="number_of_led">
                    </td>
                </tr>
            </tbody>
        </table>
        <div><br/></div>
        <table class="input">
            <tbody>
                <tr>
                    <td>
                        Set number of lit LED
                    </td>
                </tr>
                <tr>
                    <td>
                        <input type="text" id="change_lit_led"></input>
                    </td>
                </tr>
                <tr>
                    <td>
                        <!-- 
                        This will submit the request ledbar_set with value from the input form 
                        change_lit_led as paramater 
                        -->
                        <button onclick="javascript:submitSyncFromInput('ledbar_set', 'change_lit_led')">
                            Set
                        </button>
                    </td>
                </tr>
            </tbody>
        </table>
        <div><br/><br/></div>
        <table class="grid">
            <tbody>
                <tr>
                    <td colspan = "2">
                        Increase/decrease number of lit LED
                    </td>
                </tr>
                <tr>
                    <td>
                        <!-- This will submit the request ledbar_decrease -->
                        <button onclick="javascript:submitSync('ledbar_decrease')">Decrease</button>
                    </td>
                    <td>
                        <!-- This will submit the request ledbar_increase -->
                        <button onclick="javascript:submitSync('ledbar_increase')">Increase</button>
                    </td>
                </tr>
            </tbody>
        </table>
    </body>
</html>


Test it

The synchronization program should have upload the 2 new files for you.
To be absolutely sure that all your changes had bean implemented, you can write S and pressing Enter in the synchronization program.
 # s
2015-12-27 15:05:08 Request service restart

#
The steelsquid daemon is then restarted

Enter http://<ip to your raspberry>/led_bar in your browser

You should see this page:
  • Test to push the buttons and set the number of LED to be lit.

  • Also test to push the buttons connected to the GPIO
    When you do that the "Number of LED lit" value in the web should change also.

  • If you unplug the network cable or unplug the WIFI usb card all the LED should turn off and when you put it back in all should lit.

  • Press the button so you have about half the LED lit.
    In the synchronization program window type: 
    echo "" > /root/flash
    And all the LED should lit for 1 second and then go back to the number before.

That's it :-)