Domotiga/Development

Development

I certainly can use some help developing this a bit more... This help can be in the form of tips and tricks, Gambas or Domotics related, ideas, brainstorm sessions, code snippets for new drivers (also example vb code is accepted), donations so I can write code to support new hardware, kudo's etc etc ...

I guess you already found the svn repository, you are encouraged to use it, or even better, to give back your code to the community.

How can I write my own module?

If you want to support your own hardware, here are a few pointers to start with:

  • Global variables, settings.

You have to determine which settings you need, and what type they are. For example for serialport, baudrate etc. Define these at the start of Main.module below the others... Please add a letter to the name determining the type, s for string, b for boolean, i for integer etc.

'MyModule' describes an example module in the form of a class, which uses a serial port device and gets data automatically (ie no polling needed). It's a copy of the OneWire module. Replace the name 'MyModule' with a useful name for your module.

' MyModule
PUBLIC bMyModuleEnabled AS Boolean
PUBLIC sMyModuleSerialPort AS String
PUBLIC sMyModuleBaudrate AS String
PUBLIC bMyModuleDebug AS Boolean
PUBLIC hMyModule AS CMyModule

You need at least Enabled and Debug.

  • Start Database Manager from Tools menu in your Gambas IDE and create a table to hold you module's settings.

Name should be 'settings_mymodule' and type !MyISAM. Check other tables for fields you need, field id should be type integer, then fill default and current data fields. Field id = 0 is for defaults, id = 1 is for current/active settings. If you have those, they need to be loaded at the start of DomotiGa, this is done in Main.GetSettings(). Here you give the name of your module to load settings for, and the global vars will be filled with the field values you have defined.

  ' MyModule
  rResult = GetSettingTable("mymodule")
  bMyModuleEnabled = rResult!enabled
  sMyModuleSerialPort = rResult!serialport
  sMyModuleBaudrate = rResult!baudrate
  bMyModuleDebug = rResult!debug
  • Next you need to create a settings form, so the user can modify these values.

You can create a new form name !FSettingsMyModule, set border to non re sizable, and background color to TextBackground. Then copy the frame with all in it of a similar other settings form. Then try to adapt the code below this form to your settings and module.

  • We continue by creating a start and restart routine to do the initializing of your module.

Copy and/or create a routine Setup_MyModule() which looks like this (just an example).

'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' open mymodule serial port and initialize
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PRIVATE FUNCTION Setup_MyModule()

  IF bMyModuleEnabled THEN 
    WriteLog("MyModule interface enabled.")
    ' create a new MyModule class instance
    hMyModule = NEW CMyModule
    ' set the properties
    WITH hMyModule
      .Port = sMyModuleSerialPort
      .Baud = sMyModuleBaudrate
      .MyModuleDebug = bMyModuleDebug
    END WITH
    ' connect to the serial port
    IF hMyModule.Connect() THEN
      WriteLog("MyModule interface connected to Port " & sMyModuleSerialPort)
      hMyModule.Run()
    ELSE
      WriteLog("ERROR: MyModule interface FAILED to connected to Port " & sMyModuleSerialPort & "")
    END IF
  ELSE
    WriteLog("MyModule interface disabled.")
  ENDIF

END

'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' restart mymodule after settings change
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PUBLIC FUNCTION Restart_MyModule()

  IF hMyModule THEN
    hMyModule.Disconnect
    hMyModule = NULL
  END IF
  Setup_MyModule()

END

Add a call to Setup_MyModule() inside Main.Setup(), you find all the others there. Restart_MyModule() is called from the settings form, to activate new settings. If your module uses a stream be sure to close it before the program closes, to do this enter a call at the end of Main.CloseAll()

  • Create a class for your module, name CMyModule.

And fill it with the things it should do.

PROPERTY Port AS String
PROPERTY Baud AS String
PROPERTY MyModuleDebug AS Boolean

PRIVATE sPort AS String
PRIVATE sBaud AS String
PRIVATE bMyModuleDebug AS Boolean

PUBLIC hMyModule AS NEW SerialPort

PUBLIC sBuffer AS String

'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' open serial port
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PUBLIC FUNCTION Connect() AS Boolean

  ' try to close the port
  TRY hMyModule.Close

  ' get a new one
  hMyModule = NEW Serialport AS "MyModule"

  WITH hMyModule
    .PortName = sPort
    .Speed = sBaud
    .Parity = 0
    .DataBits = 8
    .StopBits = 1
    .Open()
  END WITH

  ' all ok
  RETURN TRUE

CATCH ' some errors
  Main.WriteLog("MyModule Error: " & ERROR.Text)
  RETURN FALSE

END

PUBLIC SUB MyModule_Read()

  DIM sData AS String

  READ #hMyModule, sData
  ' read and parse incoming data here... call ParseLine (sData) for example

END

PUBLIC SUB ParseLine(sStr AS String)

  DIM iDeviceId AS Integer
  DIM aScan AS String[]

  IF bMyModuleDebug THEN Main.WriteDebugLog("[MyModule] " & sStr)

  ' try to find device with address, and correct interface type.
  iDeviceId = Devices.Find("<address>", Devices.FindInterface("<interface>"))
  ' if found then update it's value
  IF iDeviceId THEN Devices.Update(iDeviceId, "<value>")

END

'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' close port
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PUBLIC FUNCTION Disconnect() AS Boolean

  ' try to close the connection
  TRY hMyModule.Close
  Main.WriteLog("MyModule serial port close.")

  ' all ok
  RETURN TRUE

CATCH ' some errors
  Main.WriteLog("MyModule Error: " & ERROR.Text)
  RETURN FALSE

END

' implement properties
FUNCTION Port_Read() AS String

  RETURN sPort

END

SUB Port_Write(Value AS String)

  sPort = Value

END

PRIVATE FUNCTION Baud_Read() AS String

  RETURN sBaud

END

PRIVATE SUB Baud_Write(Value AS String)

  sBaud = Value

END

PRIVATE FUNCTION MyModuleDebug_Read() AS Boolean

  RETURN bMyModuleDebug

END

PRIVATE SUB MyModuleDebug_Write(Value AS Boolean)

  bMyModuleDebug = Value

END

MyModule_Read() is an event that gets called when data arrives on the serial port. You can of course also write to the serialport handle 'hMyModule' using PRINT (ascii) or WRITE (binary).

  • You need to define your new devices, and device type via menu Devices -> Modules an Groups, and you maybe need to define a new interface type and protocol that goes with it, you can only do this via the database manager in the database table 'interfaces' so they can be chosen in the device editor.
  • Device editor need to be made aware of these entries and their possibilities.

This process needs to be described in more detail, but you can check out the source code until then. If your module uses a serialport (like in this example) add it's name to this list in FToolsSerialPorts.

DIM sInterfaces AS String[] = ["ctx35", "irman", "sms", "gps", "onewire", "visca", "rfxcom", "weeder"]

So it can recognize it and display the module if you defined a serial port for it.