openHAB is a widely accepted open source automation software for home, office, etc. It written in Java and is lightweight and can set up in Linux, OS X or Windows. You can run openHAB on RaspberryPi. openHAB project also includes mobile client applications for both iOS and Android. Since these applications are part of the open source project the UI of the application is not promising. But we can easily make the UI of the application better without much effort.
Customizing openHAB Android application
In this document, I will give a brief idea about, how to begin with changing the UI of the openHAB android application. I will explain how did we modify the switch and slider components in the application with our own design. You can do the same for all the layouts in the application and have the application a new look.
Changing the icons
We can easily add new icons to the application by replacing or adding the images to “/opt/openhab/webapps/images/”, make sure that the new names are used in the sitemaps “/opt/openhab/configurations/sitemaps/*.sitemap”
Changing the layout of controls
To change the UI of the openHAB application we need to update the layout files. Select layout file of the control and do the update as needed like changing the background color, style of the views, the appearance of the views, properties of the views etc. Make sure that you are not removing any views from these layouts. If we remove views from these layouts unexpected error could occur. Just focus on the appearance.
Customizing android views Switch and Slider
We also need to customize the Switch and Slider views in the application.
New theme
The application theme is also changed. We added a new theme in ..res/values/themes.xml file.
For our application we changed the layout of the Switch component is modified from
to
the slider component has changed from
to
The source changes are given below.
…res/layout/openhabwidgetlist_switchitem.xml(original)
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="?android:activatedBackgroundIndicator" android:paddingLeft="@dimen/widgetlist_item_left_margin" android:paddingRight="@dimen/widgetlist_item_right_margin"> <include android:id="@+id/switchleftlayout" layout="@layout/openhabwidgetlist_icontext" /> <android.support.v7.widget.SwitchCompat android:id="@+id/switchswitch" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="3dip" android:focusable="false" android:focusableInTouchMode="false" /> <LinearLayout android:id="@+id/listdivider" android:layout_width="fill_parent" android:layout_height="1dip" android:layout_below="@+id/switchleftlayout" android:layout_marginLeft="@dimen/widgetlist_divider_left_margin" android:layout_marginRight="@dimen/widgetlist_divider_right_margin" android:background="?android:attr/listDivider" android:orientation="horizontal" /> </RelativeLayout>
…res/layout/openhabwidgetlist_switchitem.xml(modified)
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="?attr/widgetListItemHeight" android:paddingLeft="@dimen/widgetlist_item_left_margin" android:paddingRight="@dimen/widgetlist_item_right_margin" android:background="?attr/widgetListItemBackground"> <org.openhab.habdroid.util.MySmartImageView android:layout_width="56dip" android:layout_height="56dip" android:id="@+id/widgetimage" android:layout_centerVertical="true" android:maxWidth="56dip" android:minWidth="56dip" android:maxHeight="56dip" android:minHeight="56dip" android:alpha=".50" /> <TextView android:layout_marginLeft="16dp" android:layout_marginStart="16dp" android:id="@+id/widgetlabel" android:ellipsize="end" android:maxLines="1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/widgetimage" android:layout_centerVertical="true" android:textAppearance="?android:attr/textAppearanceLarge" /> <Switch android:id="@+id/switchswitch" android:layout_width="90dp" android:layout_height="45dp" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_centerVertical="true" android:thumb="@drawable/switch_selector" android:track="@drawable/switch_track" android:checked="true" android:textOn="ON" android:textOff="OFF" android:switchTextAppearance="@style/SwitchTextAppearance" android:showText="true" /> <LinearLayout android:id="@+id/listdivider" android:layout_width="fill_parent" android:layout_height="1dp" android:layout_marginLeft="@dimen/widgetlist_divider_left_margin" android:layout_marginRight="@dimen/widgetlist_divider_right_margin" android:background="?attr/widgetListItemDivider" android:orientation="horizontal" android:layout_alignParentBottom="true"/> </RelativeLayout>
…res/layout/openhabwidgetlist_slideritem.xml(original)
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingLeft="@dimen/widgetlist_item_left_margin" android:paddingRight="@dimen/widgetlist_item_right_margin" android:background="?android:activatedBackgroundIndicator"> <include android:id="@+id/sliderleftlayout" layout="@layout/openhabwidgetlist_icontext" /> <SeekBar android:id="@+id/sliderseekbar" android:layout_width="130dip" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:max="100" /> <LinearLayout android:id="@+id/listdivider" android:layout_width="fill_parent" android:layout_height="1dip" android:background="?android:attr/listDivider" android:orientation="horizontal" android:layout_below="@+id/sliderleftlayout" android:layout_marginLeft="@dimen/widgetlist_divider_left_margin" android:layout_marginRight="@dimen/widgetlist_divider_right_margin" /> </RelativeLayout>
…res/layout/openhabwidgetlist_slideritem.xml(modified)
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/wrapper" android:layout_width="fill_parent" android:layout_height="?attr/widgetListItemHeight" android:paddingLeft="@dimen/widgetlist_item_left_margin" android:paddingRight="@dimen/widgetlist_item_right_margin" android:background="?attr/widgetListItemBackground"> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/icontextlayout" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentLeft="true"> <org.openhab.habdroid.util.MySmartImageView android:layout_width="56dip" android:layout_height="56dip" android:id="@+id/widgetimage" android:layout_centerVertical="true" android:maxWidth="56dip" android:minWidth="56dip" android:maxHeight="56dip" android:minHeight="56dip" android:alpha=".50" /> <TextView android:id="@+id/widgetlabel" android:layout_marginLeft="16dp" android:layout_marginStart="16dp" android:layout_alignTop="@id/widgetimage" android:layout_toRightOf="@id/widgetimage" android:layout_toEndOf="@id/widgetimage" android:ellipsize="end" android:maxLines="1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" /> <TextView android:id="@+id/widgetvalue" android:layout_alignTop="@id/widgetimage" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" /> <SeekBar android:id="@+id/sliderseekbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignLeft="@id/widgetlabel" android:layout_alignBottom="@id/widgetimage" android:layout_marginStart="-16dp" android:layout_marginLeft="-16dp" android:layout_marginRight="-16dp" android:layout_marginEnd="-16dp" android:progressDrawable="@drawable/seekbar_progress_drawable" android:thumbOffset="0dp" android:max="100" android:thumb="@drawable/seekbar_thumb"/> </RelativeLayout> <LinearLayout android:id="@+id/listdivider" android:layout_width="fill_parent" android:layout_height="1dp" android:background="?attr/widgetListItemDivider" android:orientation="horizontal" android:layout_alignParentBottom="true" android:layout_marginLeft="@dimen/widgetlist_divider_left_margin" android:layout_marginRight="@dimen/widgetlist_divider_right_margin" /> </RelativeLayout>
…res/drawable/seekbar_background.xml(added)
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="line"> <stroke android:width="2dp" android:color="@color/seekBarTrack"/> </shape>
…res/drawable/seekbar_progress.xml(added)
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="line"> <stroke android:width="2dp" android:color="@color/seekBarTrackPrimaryProgress"/> </shape>
…res/drawable/seekbar_progress_drawable.xml(aaded)
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@android:id/background" android:drawable="@drawable/seekbar_background"/> <item android:id="@android:id/secondaryProgress"> <clip android:drawable="@drawable/seekbar_secondary_progress" /> </item> <item android:id="@android:id/progress"> <clip android:drawable="@drawable/seekbar_progress"/> </item> </layer-list>
…res/drawable/seekbar_progress_drawable_highlighed.xml(added)
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@android:id/background" android:drawable="@drawable/seekbar_background"/> <item android:id="@android:id/secondaryProgress"> <clip android:drawable="@drawable/seekbar_secondary_progress" /> </item> <item android:id="@android:id/progress"> <clip android:drawable="@drawable/seekbar_progress_highlighted"/> </item> </layer-list>
…res/drawable/seekbar_progress_highlighted.xml(added)
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="line"> <stroke android:width="2dp" android:color="@color/seekBarTrackPrimaryProgressHighlighted"/> </shape>
…res/drawable/seekbar_secondary_progress.xml(added)
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="line"> <stroke android:width="2dp" android:color="@color/seekBarTrackSecondaryProgress"/> </shape>
…res/drawable/seekbar_thumb.xml(added)
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true"> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <size android:height="24dp" android:width="24dp"/> <solid android:color="@color/seekBarThumb" /> <stroke android:color="@color/seekBarThumbTransparent" android:width="4dp"/> </shape> </item> <item> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <size android:height="24dp" android:width="24dp"/> <solid android:color="@color/seekBarThumb" /> </shape> </item> </selector>
…res/drawable/seekbar_thumb_highlighted.xml(added)
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true"> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <size android:height="24dp" android:width="24dp"/> <solid android:color="@color/seekBarThumbHighlighted" /> <stroke android:color="@color/seekBarThumbTransparent" android:width="4dp"/> </shape> </item> <item> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <size android:height="24dp" android:width="24dp"/> <solid android:color="@color/seekBarThumbHighlighted" /> </shape> </item> </selector>
…res/drawable/switch_selector.xml(added)
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android" > <item android:state_checked="false"> <shape android:shape="oval" android:visible="true" android:dither="true" android:useLevel="false"> <stroke android:color="@android:color/transparent" android:width="4dp"/> <solid android:color="@color/colorSwitchOff"/> <size android:width="45dp" android:height="45dp" /> </shape> </item> <item android:state_checked="true"> <shape android:shape="oval" android:visible="true" android:dither="true" android:useLevel="false"> <stroke android:color="@android:color/transparent" android:width="4dp"/> <solid android:color="@color/colorSwitchOn"/> <size android:width="45dp" android:height="45dp" /> </shape> </item> </selector>
…res/drawable/switch_track.xml(added)
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_checked="false"> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" android:visible="true" android:dither="true" android:useLevel="false"> <corners android:radius="25dp"/> <solid android:color="@color/colorSwitchTrack"/> <stroke android:color="@color/colorSwitchTrackBorder" android:width="1px"/> <size android:width="90dp" android:height="45dp" /> </shape> </item> <item android:state_checked="true"> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" android:visible="true" android:dither="true" android:useLevel="false"> <corners android:radius="25dp"/> <solid android:color="@color/colorSwitchTrack"/> <stroke android:color="@color/colorSwitchTrackBorder" android:width="1px"/> <size android:width="90dp" android:height="45dp" /> </shape> </item> </selector>
…res/values/colors.xml(modified)
..... <color name="windowBackground">#000000</color> <color name="colorActionBar">#D9D9D9</color> <color name="colorSwitchTrack">#804C5266</color> <color name="colorSwitchTrackBorder">#804C5266</color> <color name="colorSwitchOn">#E3E3E5</color> <color name="colorSwitchOff">#E3E3E5</color> <color name="colorSwitchTextOff">#000000</color> <color name="colorSwitchTextOn">#4d536b</color> <color name="seekBarTrack">#80ffffff</color> <color name="seekBarTrackSecondaryProgress">#80ffffff</color> <color name="seekBarTrackPrimaryProgress">@android:color/transparent</color> <color name="seekBarThumb">#80ffffff</color> <color name="seekBarThumbTransparent">#40ffffff</color> <color name="seekBarTrackPrimaryProgressHighlighted">#ffffff</color> <color name="seekBarThumbHighlighted">#ffffff</color> <color name="widgetListDividerColor">#000000</color> <color name="textColor">#80ffffff</color> <color name="widgetBackground">#000000</color> .....
..res/values/themes.xml(modified)
.... <style name="HABDroid.Custom" parent="@style/Theme.AppCompat"> <item name="android:windowBackground">@color/windowBackground</item> <item name="customMicIcon">@android:drawable/ic_btn_speak_now</item> <item name="widgetListItemDivider">@color/widgetListDividerColor</item> <item name="widgetListItemHeight">84dp</item> <item name="widgetListItemBackground">@color/widgetBackground</item> <item name="frameWidgetDividerBackground">@color/black</item> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorAccent">@color/colorAccent</item> <item name="colorPrimaryDark">@color/colorPrimary_Dark</item> <item name="windowNoTitle">true</item> <item name="windowActionBar">false</item> <item name="windowActionBarOverlay">false</item> <item name="themedActionBarBackground">@drawable/action_bar</item> <item name="themedDrawerBackground">@color/lightBackground</item> <item name="themedHeaderTextColor">@color/colorPrimary</item> <item name="android:textColor">@color/textColor</item> </style> ....
..res/values/attrs.xml(modified)
.... <attr name="widgetListItemBackground" format="color"/> <attr name="widgetListItemHeight" format="dimension"/> ....
In the openHab server /opt/openhab/configurations/sitemaps/*.sitemap is modified to
sitemap MySmartHome label="My Smart Home"{ Frame { Switch item=g001 label="Master" icon="smart_switch" Switch item=g002 label="onoff group" icon="smart_switch" Slider item=g003 label="dimming group" icon="smart_fan" } }