Google Analytics

Wednesday, April 9, 2014

A Home Security/Automation System - Monitor changes

Monitor Update  (April 9, 2014)
Previous     Next     Table of Contents

Was finally able to get a little bit of insight into Kivy (GUI for Python), and I've updated the Monitor Screen.

Here's a picture.

I'm not going to post the code right now, as I'm debating on whether the project has reached the point where I need to move it to github.

Anyway, here's several pictures.

The first shows the yellow separator line between Zones, all Zones NORMAL, all radio buttons ACTIVE:


The next shows Zone 1 in an alarm state (it blinks first, then I acknowledge which seals it in).  Notice on the right, I've selected various radio buttons to change the state.  Zone 1 is ACTIVE, and in ALARM.  Zone 2 is INACTIVE, Zone 3 is BYPASS, Zone 4 is MONITOR, Zone 5 is TEST.  The various colors are associated with that Zone's radio button - e.g., any Zone in BYPASS will have a BLUE Zone Button.



Saturday, April 5, 2014

Kivy - Using ObjectProperty

I'm learning Kivy to use as the GUI interface to my Home Secutiry/Automation system.

This is a fairly new language, but looks to me like its going to be a good fit for my project, as well as growing in popularity.

Because it's new, there's not a lot of examples that I've been able to find, and the two books I've looked at jump a little too fast for me.

I solve this by writing a lot of small example programs to teach myself the underlying structure - this post is one of those examples.

In a MVC (Model, View, Controller), Python is performing the Control function, and Kivy is performing the View function (presentation); I don't really have a Model function in this example.

I've been having a lot of difficulty understanding the usage Kivy's ObjectProperty() call in Python.

Here's what I understand, and the examples (Python code and Kivy code) follow.

--UPDATE 4/5/14: I think it would be easier to use dynamic classes in .kv instead of the empty Python classes with 'pass'.  For example, below for Python, remove 'class Zone1' and in .kv change : to I haven't changed the code below to reflect this.
--

In Python, the following entries are made in a class:

class Zones(BoxLayout):
    labelText = ObjectProperty(None)
    basement   = ObjectProperty(None)

The two objects ('thispage' and 'basement') are references to the classes defined in the associated .ky file.

Here's the .ky file entry for those two class definitions:

:
    some_text: "This is Label text"

:
    zoneName: "Basement - Door and Windows"

Those two class definitions in the .ky file, must also have an entry in the in the .py file.  So back to the .py file to add these two classes (they aren't going to perform any logic, so I'm just setting their work to be performed to 'pass'):

class LabelText(Widget):
    pass

class Zone1(Widget):
    pass

Now back to the .ky file.  Within this file, so far, are the class definitions for Kivy - the LabelText class and the Zone1 class.  This represents the layout work that's going to be done by Kivy - the presentation.

Next I'm going to associate the Python objects 'labelText' and 'basement' with the two Python/Kivy classes 'LabelText' and 'Zone1'.

Adding a new class : to the Kivy .kv file, will give part of the association to the labelText and basement references, but it's not the final reference; there will be two more yet, where the Zone class is using the two widgets (classes) LabelText and Zone1.  

:
    labelText:   label_text
    basement:   zone1

    LabelText:
        id: label_text
    Zone1:
        id: zone1


So following Python code 'basement' entry:

    basement   = ObjectProperty(None)

Refers to the reference name assigned in Kivy .ky file to the widget id (where 'basement' is the tie to Python, and 'zone1' is the widget's ID in .ky):

    basement:   zone1

Then within Kivy, the zone1 is finally defined as the widget ID for the class instance :

    Zone1:
        id: zone1

So, bare bones, for basement/Zone1 we've got:

==== Python .py file ====

class Zone1(Widget):
    pass

class Zones(BoxLayout):
    labelText = ObjectProperty(None)
    basement   = ObjectProperty(None)


==== Kivy .ky file ====

:
    zoneName: "Basement - Door and Windows"

:
    basement:   zone1

    Zone1:
        id: zone1


Here's a PNG of the output, followed by the Python and Kivy code, with some additional features added (couple of more buttons), and a print utility (to your terminal window):



==== Python Code ====
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  TestProperties1.py
#  
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout


class LabelText(Widget):
    pass

class Zone1(Widget):
    pass

class Zone2(Widget):
    pass

class Zone3(Widget):
    pass
    
class Zones(BoxLayout):
    labelText = ObjectProperty(None)
    basement   = ObjectProperty(None)
    sunroom    = ObjectProperty(None)
    livingroom = ObjectProperty(None)
    
    def printzonenames(self):
        print("labelText: ", self.labelText.some_text)
        print("basement: ", self.basement.zoneName)
        print("sunroom: ", self.sunroom.zoneName)
        print("livingroom: ", self.livingroom.zoneName)

class TestProperties1(App):
    def build(self):
        theZones = Zones()
        theZones.printzonenames()
    


def main():
    TestProperties1().run()
    
    return 0

if __name__ == '__main__':
    main()

=======Python Code End=========

=======Kivy Code ============

#testproperties1.kv

Zones:

:
    some_text: "This is Label text"

:
    zoneName: "Basement - Door and Windows"

:
    zoneName: "Sunroom - Door and Windows"
    
:
    zoneName: "Living Room - Area"

:
    orientation: 'vertical'
    
    labelText:   label_text
    basement:   zone1
    sunroom:    zone2
    livingroom: zone3

    
    LabelText:
        id: label_text
    Zone1:
        id: zone1
    Zone2:
        id: zone2
    Zone3:
        id: zone3



    Label:
        text: label_text.some_text
    Button:
        text: zone1.zoneName
    Button:
        text: zone2.zoneName
    Button:
        text: zone3.zoneName

    
=======Kivy Code End =====    




Friday, April 4, 2014

Home Security/Automation System - Monitor Screen

Monitor Screen - under development

Previous     Next     Table of Contents

As mentioned on the previous post, I'm performing the GUI portion of the Home Security/Automation System using Kivy.

I've had quite a learning curve to get the Monitor Screen (below) to the point where it is now.  While I like Kivy, the documentation is still a struggle for me, so I have to build a lot of simple GUIs and work with them, then gradually adding complexity.

The screen below is a mockup of what I'm envisioning.  It doesn't have any logic behind it, just ability to show the zone buttons and checkboxes.

I don't like the way the checkboxes are being displayed.  With the buttons, it's easy to see the button boundary, but the checkboxes just all run together to me; can't really tell where one zone's checkboxes ends and another's begins.

So I'm researching, trying to find a way to add some sort of visual delimiter that separates the zone's checkboxes from the next zone's checkboxes.

Here's what I've got so far (first the picture, then the code - note: Kivy code is two part; a Python portion (*.py) and a Kivy language portion (*.kv).  I've posted both below.

First - the picture of the Monitor Screen (currently titled as 'Dynamic Button Text')



Here's the Python code:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  DynamicButtonText.py
#
#  http://BBQandBanjos.blogspot.com
#  

# Given a Dictionary of dynamic names,
# pick each up and assign it to the Button text.


from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.checkbox import CheckBox

class ZoneList():
    _zoneL = ["Basement","Sun Room","Den","Living Room","Front Door"]

class ZoneElements(GridLayout):
    pass

class ZoneCheckBoxes(GridLayout):
    _instance_count = -1
    _zoneNames = ZoneList._zoneL

    def __init__(self, **kwargs):
        super(ZoneCheckBoxes, self).__init__(**kwargs)
        ZoneCheckBoxes._instance_count += 1
    

class ZoneButton(Button):
    _instance_count = -1
    _zoneNames = ZoneList._zoneL
    
    def __init__(self, **kwargs):
        super(ZoneButton, self).__init__(**kwargs)
        ZoneButton._instance_count += 1

class ZoneLayout(BoxLayout):
    def __init__(self, **kwargs):
        super(ZoneLayout, self).__init__(**kwargs)
        for i in range(len(ZoneList._zoneL)):
            self.add_widget(ZoneElements())

class DynamicButtonText(App):
    pass

def main():
    DynamicButtonText().run()   #run kivy app
    
    return 0

if __name__ == '__main__':
    main()

    

========

And here's the Kivy code:


#dynamicbuttontext.kv

ZoneLayout:

:
    orientation: 'vertical'
            
:
    text: "Zone " + str(root._instance_count + 1) + ": " + root._zoneNames[root._instance_count]
#    text: "Button: "
        
:
    cols:2
    CheckBox:
        active: True
        group: "Zone " + root._zoneNames[root._instance_count]
    Label:
        text: "Active"
        
    CheckBox:
        group: "Zone " + root._zoneNames[root._instance_count]
    Label:
        text: "Inactive"
    
    CheckBox:
        group: "Zone " + root._zoneNames[root._instance_count]
    Label:
        text: "Bypass"
    
    CheckBox:
        group: "Zone " + root._zoneNames[root._instance_count]
    Label:
        text: "Monitor"
    
    CheckBox:
        group: "Zone " + root._zoneNames[root._instance_count]
    Label:
        text: "Test"


:
    cols: 2
    ZoneButton:

    ZoneCheckBoxes:

Friday, March 28, 2014

Home Security System - update

Previous      Next      TableOfContents

STATUS
It's been a while since I published an update to my project.  Seems I have too many projects!

Recently, I started this project back up.  I've made a lot of headway in programming the project in Python, with major changes to the architecture.

Here's the status as of March 28 2014:

  • It's still slated to be deployed on a Beagle Bone Black (B3)
  • It will follow a MVC (Model View Controller) paradigm.
  • The GUI display will utilize Kivy. 
  • The three major components:
    • The portion that runs on the B3 will be the portion that is responsible for monitoring the sensors.
      • The code for each sensor will run in its own thread.
    • The GUI will run distributed across a network, both local as well as Internet.
    • The Controller will run on a desktop machine.  It's currently running on Ubuntu, but since it's Python, it should also run on Mac and Windows.
    • The logger will run on the desktop machine.
    • It will support multiple monitoring nodes.
I have been actively working on this, making a lot of headway.  

TOOLS

plantuml.com
At one point, after taking a couple of days off, I realized rather than reorienting myself to the code through manually walking through the code, I should put together some Sequence Diagrams.  So at first I had drew these, but after having to update them a couple of times, I started looking around for something better suited to this task, while being free and lightweight.

I settled on 'PLANTUML.COM' for this activity.  I highly recommend it!  Now, I just keep a text file open, where I add the sequence of messages as I change the code, run plantuml tool against it, which produces a PNG output file.  This has enabled me to return to the code much faster whenever I take some time off.

Kivy
The first attempt was using TkInter, but after taking some time off and returning to this project, I wanted to take a look around and see what might be new.  I came across Kivy.  After a deep dive, I decided this was the path I was going to take.  I've been reading the following books (in addition to the kivy.org documentation):
  • Kivy: Interactive Applications in Python (Roberto Ulloa)
  • Creating Apps in Kivy (Dusty Phillips)
Of the two books, I prefer Dusty's book "Creating Apps in Kivy"

More later!!!

Tuesday, December 3, 2013

Ubuntu and NVIDIA - header problem

I recently installed a Ubuntu software update, which made use of a new Linux kernel.

On reboot, I found the GUI screen to be in this huge, clunky graphics mode, where only about 1/3 of my screen was now visible.

It was obvious something was different about usage of my NVIDIA graphics card.

I did a lot of research, and finally got it working again - until the next update that included a new kernel.  Same goes for upgrades - they also broke my NVIDIA graphics card normal operation.

One of the things my research led me to was the Bug Reports for Ubuntu.  The developers have made a deliberate decision, after identifying the problem with the updates/upgrades to kernels which causes the NVIDIA driver to not function correctly, to not include some header files that are needed.  It appears they are being 'purists' instead of making a simple addition to the distribution that would prevent this problem.

As it turns out, NVIDIA drivers need to be built for the specific kernel that is being run.  And, in order to be rebuilt, NVIDIA needs the new header files (have a look at /usr/src/linux-headers* and you should see some linux-header folders) - it needs the source header files for the new kernel, and these new source header files are deliberately not being included in the Ubuntu update/upgrades, even though the developers know this is a problem - they are willing for you, and thousands of other users, to not have a working computer and expect you to fix this problem yourself.

So - this is how I went about fixing my problem.
Note: here's a useful link.

I didn't know where my original NVIDIA driver was at, and didn't really care to find it - I wanted to make sure I was running the newest drivers.

From a high level, this is what I did - I am not saying this will work for you, and in fact it may cause you problems with your system.  More detailed information will follow.

Outline:
( I am not an expert.  I am not responsible for any problems caused from use of this information.  You assume all risk.  If something goes wrong, I will not help you.):

  • I downloaded the NVIDIA driver for my card and Operating System.
  • I changed the NVIDIA driver script to executable
  • I went to a user console (this is not a X-Terminal) - NVIDIA wants the X GUI stopped.
  • stop the X GUI
  • I moved to my download directory where I placed the NVIDIA driver
  • I ran the NVIDIA driver script - it will report an error for missing source linux-header files
  • I noted the missing source linux-header file
  • I downloaded and installed the missing linux-header file
  • I ran again the NVIDIA driver script - this time it succeeded
  • I rebooted


From a detailed level, this is what I did - I am not saying this will work for you, and in fact it may cause you problems with your system.  More detailed information will follow.


Details:
 ( I am not an expert.  I am not responsible for any problems from use of this information.  You assume all risk.  If something goes wrong, I will not help you.):


  1. I made a backup of my Operating System before proceeding, in case something went wrong), and placed this backup onto a different hard drive. I know how to reinstall this backup successfully, having tested doing so in the past. 
  2. First, I downloaded the NVIDIA driver for my operating system (64 bit), and for my graphics card (series 500), from this site (current as of 12/3/13).  
    1. My default download location is ~/Downloads.  http://www.nvidia.com/Download/index.aspx
  3. I went to a user console (this is NOT an X-Terminal)
    1. I Depressed simultaneously these keys: Ctrl-Alt-F1
    2. I logged into my computer with my userid and password
  4. I stopped the X GUI - (NVIDIA shell script requires this)
    1. sudo stop lightdm
  5. I changed to my Downloads directory where I had placed my NVIDIA driver
    1. cd ~/Downloads
  6. I changed the NVIDIA driver script to be executable (my downloaded driver was named NVIDIA*.run   - the * is mine, to keep from typing the whole string)
    1. sudo chmod +x NVIDIA*.run
  7. I executed the NVIDIA*.run shell script
    1. sudo sh NVIDIA*.run
    2. I selected Yes to all questions.
    3. This should produce an error message - if it had not,  I would have tried rebooting now, as I was probably good to go)
  8. I Noted the error message where it mentions the 'linux-headers' source file - this is the header files the NVIDIA driver needed to be download and installed
  9. I obtained the specific linux-header source file identified by the NVIDIA.run script and installed it
    1. sudo apt-get install linux-header-THE-FULL-NAME-I-OBTAINED-FROM-ERROR-MSG
  10. I re-ran the NVIDIA*.run shell script
    1. sudo sh NVIDIA*.run
    2. I selected Yes to all questions
    3. It reported success
  11. I rebooted my compuer
    1. sudo reboot
  12. My computer rebooted, and my problem was fixed.