I use a HabPanel widget to adjust a specific String Item that holds a JSON of a “Profile”. For example, one item might look like this:
Profilestore_json_1:
{"label":"Adaptive Light Brightness","type":"percentage","intervals": {"0":12,"1":13,"2":13,"3":13,"4":11,"5":15,"6":33,"7":64,"8":81,"9":91,"10":99,"11":100,"12":99,"13":97,"14":97,"15":94,"16":92,"17":89,"18":85,"19":74,"20":57,"21":40,"22":30,"23":20}}
and this renders to a widget that looks like this:
Also, there’s a nifty little popup settings panel too that appears when you press the button:
With this widget, I can adjust the sliders to change the hourly target value, and in the settings panel, I can change the name and type of the profile (as stored in the JSON) along with resetting the whole thing to default values (hardcoded ones).
In the background, there’s also a second item that receives commands, so when I adjust a slider it sends a command to a designated “input” item and then a rule adjusts the “store” item. In the log, this looks like so:
Item 'Profilestore_json_1_input' received command {"interval":"6","value":"41"}
Item 'Profilestore_json_1' received command {"label":"Adaptive Light Brightness","type":"percentage","intervals": {"0":12,"1":13,"2":13,"3":13,"4":11,"5":15,"6":41,"7":64,"8":81,"9":91,"10":99,"11":100,"12":99,"13":97,"14":97,"15":94,"16":92,"17":89,"18":85,"19":74,"20":57,"21":40,"22":30,"23":20}}
Ultimately, I think it would be possible to do this without the separate “input” item, but handling it with a rule was easier for me.
Here’s the code for the HabPanel Widget:
<style>
/*CHROME*/
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 100%;
background: transparent;
border: none;
border-radius: 3px;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
border: none;
height: 16px;
width: 16px;
border-radius: 50%;
background: dodgerblue;
margin-top: -4px;
}
input[type=range]:focus {
outline: none;
}
input[type=range]:focus::-webkit-slider-runnable-track {
background: #ccc;
}
/*FIREFOX*/
input[type=range][orient=vertical]
{
writing-mode: bt-lr; /* IE */
-webkit-appearance: slider-vertical; /* WebKit */
width: 100%;
height: 100%;
padding: 0 5px;
background-color: transparent;
}
input[type=range]{
/* fix for FF unable to apply focus style bug */
border: 1px solid transparent;
/*required for proper track sizing in FF*/
width: 300px;
}
input[type=range]::-moz-range-track {
width: 100%;
height: 100%;
background: white;
border: none;
border-radius: 3px;
}
input[type=range]::-moz-range-thumb {
border: none;
height: 16px;
width: 16px;
border-radius: 50%;
background: dodgerblue;
}
/*hide the outline behind the border*/
input[type=range]:-moz-focusring{
outline: 1px solid white;
outline-offset: -1px;
}
input[type=range]:focus::-moz-range-track {
background: #ccc;
}
.grapharea {
background-color: #acacac;
color: black;
padding: 20px;
}
table {
table-layout: fixed;
width: 100%;
}
td {
width: 4%;
}
.topbar {
position: relative;
margin: auto;
width: 90%;
height: 10%;
}
.grapharea {
position: relative;
margin: auto;
width: 90%
}
.rotate {
transform: rotate(90deg);
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
-o-transform: rotate(90deg);
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
}
</style>
<!-- POPUP SCRIPT -->
<script type="text/ng-template" id="editProfileName2.html">
<div class="container" style="padding: 30px; border: 1px solid #456;">
<a ng-click="$close()" class="pull-right btn btn-danger">X</a>
<h3 style="color: white">Adjust profile settings</h3>
<br></br>
<h4 style="color: white">Change Profile Name</h4>
<div class="form-inline">
<div class="form-group">
<input type="text" class="form-control" no-snap-drag="true"
ng-model="newlabel" ng-value="$eval(getItem(config.p_item).state).label"></input>
<button type="button" class="btn btn-primary"
ng-click="sendCmd(getItem(config.p_item).name.concat('_input'), '{"rename":"'.concat(newlabel).concat('"}'))">Update</button>
</div>
</div>
<h4 style="color: white">Change Type </h4>
<p style="color: white">Currently set to: <font style="color: DodgerBlue">{{$eval(getItem(config.p_item).state).type}}</font></p>
<div class="btn-group" role="group" aria-label="Basic example">
<button type="button" class="btn btn-secondary" ng-click="sendCmd(getItem(config.p_item).name.concat('_input'), '{"retype":"percentage"}')">Percentage</button>
<button type="button" class="btn btn-secondary" ng-click="sendCmd(getItem(config.p_item).name.concat('_input'), '{"retype":"temperature"}')">Temperature</button>
<button type="button" class="btn btn-secondary" ng-click="sendCmd(getItem(config.p_item).name.concat('_input'), '{"retype":"boolean"}')">Boolean</button>
</div>
<br></br>
<div>
<button type="button" class="btn btn-alert"
ng-click="sendCmd(getItem(config.p_item).name.concat('_input'), '{"reset":""}' )">Reset Profile !</button>
</div>
</div>
</script>
<!-- END POPUP SCRIPT -->
<div class="topbar">
<h4 style="float: left">
Profile: {{$eval(getItem(config.p_item).state).label}}
</h4>
<button style="float: right" class="btn btn-default" ng-click="openModal('editProfileName2.html', true, 'lg')">
Settings
</button>
</div>
<br style="clear: both"></br>
<div class="grapharea">
<table>
<tr>
<td>hr:</td>
<td ng-repeat="c in ['00','01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20','21','22','23']">
<p>{{c}}</p>
</td>
</tr>
<!--TEMPERATURE-->
<tr ng-if="$eval(getItem(config.p_item).state).type == 'temperature'">
<td class="rotate">
Temp.
</td>
<td class="" ng-repeat="c in [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]">
<div ng-init="intervalvalue = $eval(getItem(config.p_item).state).intervals[$index]">
<input class="slider" orient="vertical" type="range" ng-model="intervalvalue" name="string" min="8" max="26" step="0.5" ng-mouseup="sendCmd(getItem(config.p_item).name.concat('_input'), '{"interval":"'.concat($index).concat('","value":"'.concat(intervalvalue).concat('"}')))"></input>
<p class="rotate"> {{intervalvalue}}</p>
</div>
</td>
</tr>
<!--PERCENTAGE-->
<tr ng-if="$eval(getItem(config.p_item).state).type == 'percentage'">
<td class="rotate">
%
</td>
<td class="" ng-repeat="c in [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]">
<div ng-init="intervalvalue = $eval(getItem(config.p_item).state).intervals[$index]">
<input class="slider" orient="vertical" type="range" ng-model="intervalvalue" name="string" min="0" max="100" step="1" ng-mouseup="sendCmd(getItem(config.p_item).name.concat('_input'), '{"interval":"'.concat($index).concat('","value":"'.concat(intervalvalue).concat('"}')))"></input>
<p class="rotate"> {{intervalvalue}}</p>
</div>
</td>
</tr>
<!--BOOLEAN-->
<tr ng-if="$eval(getItem(config.p_item).state).type == 'boolean'">
<td class="rotate">
I/O
</td>
<td class="" ng-repeat="c in [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]">
<div ng-init="intervalvalue = $eval(getItem(config.p_item).state).intervals[$index]">
<input class="slider" orient="vertical" type="range" ng-model="intervalvalue" name="string" min="0" max="1" step="1" ng-mouseup="sendCmd(getItem(config.p_item).name.concat('_input'), '{"interval":"'.concat($index).concat('","value":"'.concat(intervalvalue).concat('"}')))"></input>
<p class="rotate"> {{intervalvalue}}</p>
</div>
</td>
</tr>
<tr>
<td>
<p></p>
</td>
<td ng-if="$eval(getItem(config.p_item).state).type == 'temperature'" ng-repeat="c in [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]">
<p class="rotate" > °C</p>
</td>
<td ng-if="$eval(getItem(config.p_item).state).type == 'percentage'" ng-repeat="c in [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]">
<p class="rotate" > %</p>
</td>
</tr>
</table>
</div>
Now, my question:
How can I recreate this widget as an OH3 F7-Card Widget?
Admittedly, I’m not that good at programming, and even worse at web development, but the whole YAML thing doesn’t make nearly as much sense to me as writing the HTML for HabPanel widgets. I don’t know where to start, and since it’s much more niche, I haven’t found any resources outside of the OH community that could help teach me how to use it and the F7 stuff.