openhab-scripting 2.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/workflow.yml +327 -0
- data/.gitignore +17 -0
- data/.java-version +1 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +113 -0
- data/Gemfile +28 -0
- data/Gemfile.lock +245 -0
- data/Guardfile +35 -0
- data/LICENSE +277 -0
- data/README.md +23 -0
- data/Rakefile +406 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/config/userdata/config/org/openhab/restauth.config +3 -0
- data/cucumber.yml +1 -0
- data/docs/_config.yml +135 -0
- data/docs/contributing/index.md +47 -0
- data/docs/examples/conversions.md +123 -0
- data/docs/examples/index.md +61 -0
- data/docs/index.md +19 -0
- data/docs/installation/index.md +26 -0
- data/docs/motivation/index.md +27 -0
- data/docs/usage/execution.md +9 -0
- data/docs/usage/execution/delay.md +48 -0
- data/docs/usage/execution/otherwise.md +30 -0
- data/docs/usage/execution/run.md +70 -0
- data/docs/usage/execution/triggered.md +48 -0
- data/docs/usage/guards.md +51 -0
- data/docs/usage/guards/between.md +30 -0
- data/docs/usage/guards/not_if.md +41 -0
- data/docs/usage/guards/only_if.md +40 -0
- data/docs/usage/index.md +11 -0
- data/docs/usage/items.md +66 -0
- data/docs/usage/items/contact.md +84 -0
- data/docs/usage/items/dimmer.md +147 -0
- data/docs/usage/items/groups.md +76 -0
- data/docs/usage/items/number.md +225 -0
- data/docs/usage/items/string.md +49 -0
- data/docs/usage/items/switch.md +85 -0
- data/docs/usage/misc.md +7 -0
- data/docs/usage/misc/actions.md +108 -0
- data/docs/usage/misc/duration.md +21 -0
- data/docs/usage/misc/gems.md +25 -0
- data/docs/usage/misc/logging.md +21 -0
- data/docs/usage/misc/metadata.md +128 -0
- data/docs/usage/misc/store_states.md +42 -0
- data/docs/usage/misc/time_of_day.md +69 -0
- data/docs/usage/misc/timers.md +67 -0
- data/docs/usage/rule.md +43 -0
- data/docs/usage/things.md +29 -0
- data/docs/usage/triggers.md +8 -0
- data/docs/usage/triggers/changed.md +57 -0
- data/docs/usage/triggers/channel.md +54 -0
- data/docs/usage/triggers/command.md +69 -0
- data/docs/usage/triggers/cron.md +19 -0
- data/docs/usage/triggers/every.md +76 -0
- data/docs/usage/triggers/updated.md +78 -0
- data/lib/openhab.rb +39 -0
- data/lib/openhab/configuration.rb +16 -0
- data/lib/openhab/core/cron.rb +27 -0
- data/lib/openhab/core/debug.rb +34 -0
- data/lib/openhab/core/dsl.rb +47 -0
- data/lib/openhab/core/dsl/actions.rb +107 -0
- data/lib/openhab/core/dsl/entities.rb +103 -0
- data/lib/openhab/core/dsl/gems.rb +29 -0
- data/lib/openhab/core/dsl/group.rb +91 -0
- data/lib/openhab/core/dsl/items/items.rb +39 -0
- data/lib/openhab/core/dsl/items/number_item.rb +217 -0
- data/lib/openhab/core/dsl/items/string_item.rb +102 -0
- data/lib/openhab/core/dsl/monkey_patch/actions/actions.rb +4 -0
- data/lib/openhab/core/dsl/monkey_patch/actions/script_thing_actions.rb +22 -0
- data/lib/openhab/core/dsl/monkey_patch/events.rb +5 -0
- data/lib/openhab/core/dsl/monkey_patch/events/item_command.rb +13 -0
- data/lib/openhab/core/dsl/monkey_patch/events/item_state_changed.rb +25 -0
- data/lib/openhab/core/dsl/monkey_patch/events/thing_status_info.rb +26 -0
- data/lib/openhab/core/dsl/monkey_patch/items/contact_item.rb +54 -0
- data/lib/openhab/core/dsl/monkey_patch/items/dimmer_item.rb +125 -0
- data/lib/openhab/core/dsl/monkey_patch/items/group_item.rb +27 -0
- data/lib/openhab/core/dsl/monkey_patch/items/items.rb +130 -0
- data/lib/openhab/core/dsl/monkey_patch/items/metadata.rb +259 -0
- data/lib/openhab/core/dsl/monkey_patch/items/switch_item.rb +86 -0
- data/lib/openhab/core/dsl/monkey_patch/ruby/number.rb +69 -0
- data/lib/openhab/core/dsl/monkey_patch/ruby/range.rb +46 -0
- data/lib/openhab/core/dsl/monkey_patch/ruby/ruby.rb +5 -0
- data/lib/openhab/core/dsl/monkey_patch/types/decimal_type.rb +24 -0
- data/lib/openhab/core/dsl/monkey_patch/types/on_off_type.rb +41 -0
- data/lib/openhab/core/dsl/monkey_patch/types/open_closed_type.rb +25 -0
- data/lib/openhab/core/dsl/monkey_patch/types/percent_type.rb +23 -0
- data/lib/openhab/core/dsl/monkey_patch/types/types.rb +7 -0
- data/lib/openhab/core/dsl/property.rb +85 -0
- data/lib/openhab/core/dsl/rule/channel.rb +41 -0
- data/lib/openhab/core/dsl/rule/cron.rb +115 -0
- data/lib/openhab/core/dsl/rule/guard.rb +99 -0
- data/lib/openhab/core/dsl/rule/item.rb +207 -0
- data/lib/openhab/core/dsl/rule/rule.rb +374 -0
- data/lib/openhab/core/dsl/rule/triggers.rb +77 -0
- data/lib/openhab/core/dsl/states.rb +63 -0
- data/lib/openhab/core/dsl/things.rb +93 -0
- data/lib/openhab/core/dsl/time_of_day.rb +203 -0
- data/lib/openhab/core/dsl/timers.rb +85 -0
- data/lib/openhab/core/dsl/types/quantity.rb +255 -0
- data/lib/openhab/core/dsl/units.rb +41 -0
- data/lib/openhab/core/duration.rb +69 -0
- data/lib/openhab/core/log.rb +175 -0
- data/lib/openhab/core/patch_load_path.rb +7 -0
- data/lib/openhab/core/startup_delay.rb +22 -0
- data/lib/openhab/osgi.rb +52 -0
- data/lib/openhab/version.rb +9 -0
- data/openhab-scripting.gemspec +30 -0
- data/openhab_rules/warmup.rb +5 -0
- metadata +157 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
---
|
2
|
+
layout: default
|
3
|
+
title: Contact
|
4
|
+
nav_order: 3
|
5
|
+
has_children: false
|
6
|
+
parent: Items
|
7
|
+
grand_parent: Usage
|
8
|
+
---
|
9
|
+
|
10
|
+
# Contact Item
|
11
|
+
|
12
|
+
This class is aliased to **Contact** so you can compare compare item types using ` item.is_a? Contact or grep(Contact)`
|
13
|
+
|
14
|
+
|
15
|
+
| Method | Description | Example |
|
16
|
+
| ------- | ------------------------------------ | ----------------------------------------- |
|
17
|
+
| open? | Returns true if item state == OPEN | `puts "#{item} is closed." if item.open?` |
|
18
|
+
| closed? | Returns true if item state == CLOSED | `puts "#{item} is off." if item.closed` |
|
19
|
+
|
20
|
+
|
21
|
+
##### Examples
|
22
|
+
|
23
|
+
`open?`/`closed?` checks state of contact
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# Log open contacts
|
27
|
+
Contacts.select(&:open?).each { |contact| logger.info("Contact #{contact.id} is open")}
|
28
|
+
|
29
|
+
# Log closed contacts
|
30
|
+
Contacts.select(&:closed?).each { |contact| logger.info("Contact #{contact.id} is closed")}
|
31
|
+
|
32
|
+
```
|
33
|
+
|
34
|
+
Contacts can be selected in an enumerable with grep.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
# Get all Contacts
|
38
|
+
items.grep(Contact)
|
39
|
+
.each { |contact| logger.info("#{contact.id} is a Contact") }
|
40
|
+
```
|
41
|
+
|
42
|
+
Contacts states work in grep.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
# Log all open contacts in a group
|
46
|
+
Contacts.grep(OPEN)
|
47
|
+
.each { |contact| logger.info("#{contact.id} is in #{contact}") }
|
48
|
+
|
49
|
+
# Log all closed contacts in a group
|
50
|
+
Contacts.grep(CLOSED)
|
51
|
+
.each { |contact| logger.info("#{contact.id} is in #{contact}") }
|
52
|
+
|
53
|
+
```
|
54
|
+
|
55
|
+
Contact states work in case statements.
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
#Log if contact is open or closed
|
59
|
+
case TestContact
|
60
|
+
when (OPEN)
|
61
|
+
logger.info("#{TestContact.id} is open")
|
62
|
+
when (CLOSED)
|
63
|
+
logger.info("#{TestContact.id} is closed")
|
64
|
+
end
|
65
|
+
```
|
66
|
+
|
67
|
+
|
68
|
+
Other examples
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
rule 'Log state of all doors on system startup' do
|
72
|
+
on_start
|
73
|
+
run do
|
74
|
+
Doors.each do |door|
|
75
|
+
case door
|
76
|
+
when OPEN then logger.info("#{door.id} is Open")
|
77
|
+
when CLOSED then logger.info("#{door.id} is Open")
|
78
|
+
else logger.info("#{door.id} is not initialized")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
```
|
@@ -0,0 +1,147 @@
|
|
1
|
+
---
|
2
|
+
layout: default
|
3
|
+
title: Dimmer
|
4
|
+
nav_order: 2
|
5
|
+
has_children: false
|
6
|
+
parent: Items
|
7
|
+
grand_parent: Usage
|
8
|
+
---
|
9
|
+
|
10
|
+
# Dimmer
|
11
|
+
|
12
|
+
DimmerItem is aliased to **Dimmer** so you can compare compare item types using
|
13
|
+
|
14
|
+
`item.is_a? Dimmer or grep(Dimmer)`
|
15
|
+
|
16
|
+
|
17
|
+
| Method | Parameters | Description | Example |
|
18
|
+
| -------- | ------------------ | -------------------------------------------- | ----------------------------------------------- |
|
19
|
+
| truthy? | | Item state not UNDEF, not NULL and is ON | `puts "#{item.name} is truthy" if item.truthy?` |
|
20
|
+
| on | | Send command to turn item ON | `item.on` |
|
21
|
+
| off | | Send command to turn item OFF | `item.off` |
|
22
|
+
| on? | | Returns true if item state == ON | `puts "#{item.name} is on." if item.on?` |
|
23
|
+
| off? | | Returns true if item state == OFF | `puts "#{item.name} is off." if item.off?` |
|
24
|
+
| dim | amount (default 1) | Dim the switch the specified amount | `DimmerSwitch.dim` |
|
25
|
+
| - | amount | Subtract the supplied amount from DimmerItem | `DimmerSwitch << DimmerSwitch - 5` |
|
26
|
+
| brighten | amount (default 1) | Brighten the switch the specified amount | `DimmerSwitch.brighten` |
|
27
|
+
| + | amount | Add the supplied amount from the DimmerItem | `DimmerSwitch << DimmerSwitch + 5` |
|
28
|
+
|
29
|
+
|
30
|
+
## Examples
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
DimmerOne << DimmerOne - 5
|
34
|
+
DimmerOne << 100 - DimmerOne
|
35
|
+
|
36
|
+
```
|
37
|
+
|
38
|
+
`on`/`off` sends commands to a Dimmer
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
# Turn on all dimmers in group
|
42
|
+
Dimmers.each(&:on)
|
43
|
+
|
44
|
+
# Turn off all dimmers in group
|
45
|
+
Dimmers.each(&:off)
|
46
|
+
```
|
47
|
+
|
48
|
+
`on?`/`off?` Checks state of dimmer
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
# Turn on switches that are off
|
52
|
+
Dimmers.select(&:off?).each(&:on)
|
53
|
+
|
54
|
+
# Turn off switches that are on
|
55
|
+
Dimmers.select(&:on?).each(&:off)
|
56
|
+
```
|
57
|
+
|
58
|
+
`dim` dims the specified amount, defaulting to 1. If 1 is the amount, the decrease command is sent, otherwise the current state - amount is sent as a command.
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
DimmerOne.dim
|
62
|
+
DimmerOne.dim 2
|
63
|
+
```
|
64
|
+
|
65
|
+
`brighten` brightens the specified amount, defaulting to 1. If 1 is the amount, the increase command is sent, otherwise the current state + amount is sent as a command.
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
DimmerOne.brighten
|
69
|
+
DimmerOne.brighten 2
|
70
|
+
```
|
71
|
+
|
72
|
+
Dimmers can be selected in an enumerable with grep.
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
# Get all dimmers
|
76
|
+
items.grep(Dimmer)
|
77
|
+
.each { |dimmer| logger.info("#{dimmer.id} is a Dimmer") }
|
78
|
+
```
|
79
|
+
|
80
|
+
Dimmers work with ranges and can be used in grep.
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
# Get dimmers with a state of less than 50
|
84
|
+
items.grep(Dimmer)
|
85
|
+
.grep(0...50)
|
86
|
+
.each { |item| logger.info("#{item.id} is less than 50") }
|
87
|
+
```
|
88
|
+
|
89
|
+
Dimmers can also be used in case statements with ranges.
|
90
|
+
```ruby
|
91
|
+
#Log dimmer states partioning aat 50%
|
92
|
+
items.grep(Dimmer)
|
93
|
+
.each do |dimmer|
|
94
|
+
case dimmer
|
95
|
+
when (0..50)
|
96
|
+
logger.info("#{dimmer.id} is less than 50%")
|
97
|
+
when (51..100)
|
98
|
+
logger.info("#{dimmer.id} is greater than 50%")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
Other examples
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
rule 'Dim a switch on system startup over 100 seconds' do
|
107
|
+
on_start
|
108
|
+
100.times do
|
109
|
+
run { DimmerSwitch.dim }
|
110
|
+
delay 1.second
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
```
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
rule 'Dim a switch on system startup by 5, pausing every second' do
|
118
|
+
on_start
|
119
|
+
100.step(-5, 0) do | level |
|
120
|
+
run { DimmerSwitch << level }
|
121
|
+
delay 1.second
|
122
|
+
end
|
123
|
+
end
|
124
|
+
```
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
rule 'Turn off any dimmers curently on at midnight' do
|
128
|
+
every :day
|
129
|
+
run do
|
130
|
+
items.grep(Dimmer)
|
131
|
+
.select(&:on?)
|
132
|
+
.each(&:off)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
rule 'Turn off any dimmers set to less than 50 at midnight' do
|
139
|
+
every :day
|
140
|
+
run do
|
141
|
+
items.grep(Dimmer)
|
142
|
+
.grep(1...50)
|
143
|
+
.each(&:off)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
```
|
147
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
---
|
2
|
+
layout: default
|
3
|
+
title: Groups
|
4
|
+
nav_order: 5
|
5
|
+
has_children: false
|
6
|
+
parent: Items
|
7
|
+
grand_parent: Usage
|
8
|
+
---
|
9
|
+
|
10
|
+
# Groups
|
11
|
+
|
12
|
+
A group can be accessed directly by name, to access all groups use the `groups` method.
|
13
|
+
|
14
|
+
|
15
|
+
## Group Methods
|
16
|
+
|
17
|
+
| Method | Description |
|
18
|
+
| ------------------ | ----------------------------------------------------------------------------------------------- |
|
19
|
+
| group | Access Group Item |
|
20
|
+
| items | Used to inform a rule that you want it to operate on the items in the group (see example below) |
|
21
|
+
| groups | Direct subgroups of this group |
|
22
|
+
| set methods | All methods [here](https://ruby-doc.org/stdlib-2.5.0/libdoc/set/rdoc/Set.html) |
|
23
|
+
| enumerable methods | All methods [here](https://ruby-doc.org/core-2.5.0/Enumerable.html) |
|
24
|
+
|
25
|
+
|
26
|
+
## Examples
|
27
|
+
|
28
|
+
Given the following
|
29
|
+
|
30
|
+
```
|
31
|
+
Group House
|
32
|
+
// Location perspective
|
33
|
+
Group GroundFloor (House)
|
34
|
+
Group Livingroom (GroundFloor)
|
35
|
+
// Functional perspective
|
36
|
+
Group Sensors (House)
|
37
|
+
Group Temperatures (Sensors)
|
38
|
+
|
39
|
+
Number Livingroom_Temperature "Living Room temperature" (Livingroom, Temperatures)
|
40
|
+
Number Bedroom_Temp "Bedroom temperature" (GroundFloor, Temperatures)
|
41
|
+
Number Den_Temp "Den temperature" (GroundFloor, Temperatures)
|
42
|
+
```
|
43
|
+
|
44
|
+
The following are log lines and the output after the comment
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
#Operate on items in a group using enumerable methods
|
48
|
+
logger.info("Total Temperatures: #{Temperatures.count}") #Total Temperatures: 3'
|
49
|
+
logger.info("Temperatures: #{House.sort_by(&:label).map(&:label).join(', ')}") #Temperatures: Bedroom temperature, Den temperature, Living Room temperature'
|
50
|
+
|
51
|
+
#Access to the group object via the 'group' method
|
52
|
+
logger.info("Group: #{Temperatures.group.name}" # Group: Temperatures'
|
53
|
+
|
54
|
+
#Operates on items in nested groups using enumerable methods
|
55
|
+
logger.info("House Count: #{House.count}") # House Count: 3
|
56
|
+
llogger.info("Items: #{House.sort_by(&:label).map(&:label).join(', ')}") # Items: Bedroom temperature, Den temperature, Living Room temperature
|
57
|
+
|
58
|
+
#Access to sub groups using the 'groups' method
|
59
|
+
logger.info("House Sub Groups: #{House.groups.count}") # House Sub Groups: 2
|
60
|
+
logger.info("Groups: #{House.groups.sort_by(&:id).map(&:id).join(', ')}") # Groups: GroundFloor, Sensors
|
61
|
+
|
62
|
+
```
|
63
|
+
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
rule 'Turn off any switch that changes' do
|
67
|
+
changed Switches.items
|
68
|
+
triggered &:off
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
Built in [enumerable](https://ruby-doc.org/core-2.5.1/Enumerable.html)/[set](https://ruby-doc.org/stdlib-2.5.1/libdoc/set/rdoc/Set.html) functions can be applied to groups.
|
73
|
+
```ruby
|
74
|
+
logger.info("Max is #{Temperatures.max}")
|
75
|
+
logger.info("Min is #{Temperatures.min}")
|
76
|
+
```
|
@@ -0,0 +1,225 @@
|
|
1
|
+
---
|
2
|
+
layout: default
|
3
|
+
title: Number
|
4
|
+
nav_order: 4
|
5
|
+
has_children: false
|
6
|
+
parent: Items
|
7
|
+
grand_parent: Usage
|
8
|
+
---
|
9
|
+
|
10
|
+
|
11
|
+
#### Number Item
|
12
|
+
|
13
|
+
| Method | Parameters | Description | Example |
|
14
|
+
| --------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
15
|
+
| truthy? | | Item state not UNDEF, not NULL and is not Zero | `puts "#{item.name} is truthy" if item.truthy?` |
|
16
|
+
| +,-,\*,/ | amount | Perform the operation between the state of the number item and the supplied value* | `NumberItem << NumberItem - 5` or `NumberItem << 10 + NumberItem` |
|
17
|
+
| \| | unit | Convert the supplied NumberItem to the supplied unit. Unit can either be a Unit class or string representation of the symbol, returns a Quantity object. | `NumberItem` | `ImperialUnits::FAHRENHEIT` or `NumberItem `|`'°F'` |
|
18
|
+
| to_d | | Returns the state as a BigDecimal or nil if state is UNEF or NULL | `NumberOne.to_d` |
|
19
|
+
| to_i | | Returns the state as an Integer or nil if state is UNEF or NULL | `NumberOne.to_i` |
|
20
|
+
| to_f | | Returns the state as a Float or nil if state is UNEF or NULL | `NumberOne.to_f` |
|
21
|
+
| dimension | | Returns the dimension of the Number Item, nil if the number is dimensionless | `Numberone.dimension` |
|
22
|
+
| Numeric Methods | | All methods for [Ruby Numeric](https://ruby-doc.org/core-2.5.0/Numeric.html) | |
|
23
|
+
|
24
|
+
Math operations for dimensionless numbers return a type of [Ruby BigDecimal](https://ruby-doc.org/stjjdlib-2.5.1/libdoc/bigdecimal/rdoc/BigDecimal.html). Check [Quantities section](#Quantities) for details of how math operations impact dimensioned numbers.
|
25
|
+
|
26
|
+
|
27
|
+
##### Examples
|
28
|
+
|
29
|
+
Math operations can be performed directly on the NumberItem
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
# Add 5 to a number item
|
33
|
+
NumberOne << NumberOne + 5
|
34
|
+
|
35
|
+
# Add Number item to 5
|
36
|
+
NumberOne << 5 + NumberOne
|
37
|
+
|
38
|
+
```
|
39
|
+
|
40
|
+
Number Items can be selected in an enumerable with grep.
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
# Get all NumberItems
|
44
|
+
items.grep(NumberItem)
|
45
|
+
.each { |number| logger.info("#{number.id} is a Number Item") }
|
46
|
+
```
|
47
|
+
|
48
|
+
Number Item work with ranges and can be used in grep.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
# Get numbers in group Numbers with a state of less than 50
|
52
|
+
# Get all NumberItems less than 50
|
53
|
+
Numbers.grep(0...50)
|
54
|
+
.each { |number| logger.info("#{number.id} is less than 50") }
|
55
|
+
```
|
56
|
+
|
57
|
+
Number Items can also be used in case statements with ranges.
|
58
|
+
```ruby
|
59
|
+
#Check if number items is less than 50
|
60
|
+
case NumberOne
|
61
|
+
when (0...50)
|
62
|
+
logger.info("#{NumberOne.id} is less than 50")
|
63
|
+
when (50..100)
|
64
|
+
logger.info("#{NumberOne.id} is greater than 50")
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
|
69
|
+
#### Quantities
|
70
|
+
Quantities are part of the [Units of Measurement](https://www.openhab.org/docs/concepts/units-of-measurement.html) framework in OpenHAB. The quantity object acts as ruby wrapper around the OpenHAB QuantityType.
|
71
|
+
|
72
|
+
| Method | Parameters | Description | Example |
|
73
|
+
| ------------------ | ---------- | -------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
74
|
+
| +,-,\*,/,-(negate) | amount | Perform the operation between the state of the number item and the supplied value* | `NumberItem << NumberItem - 5` or `NumberItem << 10 + NumberItem` |
|
75
|
+
| \| | unit | Convert the supplied Quantity to the supplied unit. Unit can either be a Unit class or string representation of the symbol | `NumberItem` | `ImperialUnits::FAHRENHEIT` or `NumberItem `|`'°F'` |
|
76
|
+
| quantity | | Returns the underlying OpenHAB QuantityType object | `Numberone.dimension` |
|
77
|
+
| Numeric Methods | | All methods for [Ruby Numeric](https://ruby-doc.org/core-2.5.0/Numeric.html) | |
|
78
|
+
|
79
|
+
###### Examples
|
80
|
+
|
81
|
+
Quantity types can perform math operations between them.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
Quantity.new('50 °F') + -Quantity.new('25 °F') = 25.0 °F
|
85
|
+
Quantity.new('100 °F') / Quantity.new('2 °F') = 50
|
86
|
+
Quantity.new('50 °F') * Quantity.new('2 °F') = 100 °F
|
87
|
+
Quantity.new('50 °F') - Quantity.new('25 °F') = 25 °F
|
88
|
+
Quantity.new('50 °F') + Quantity.new('50 °F') = 100 °F
|
89
|
+
```
|
90
|
+
|
91
|
+
If the operand is a string it will be automatically converted into a Quantity.
|
92
|
+
```ruby
|
93
|
+
Quantity.new('100 °F') / '2 °F' = 50
|
94
|
+
Quantity.new('50 °F') * '2 °F' = 100 °F
|
95
|
+
Quantity.new('50 °F') - '25 °F' = 25 °F
|
96
|
+
Quantity.new('50 °F') + '50 °F' = 100 °F
|
97
|
+
```
|
98
|
+
|
99
|
+
If the operand is a number, it will be unit-less, but the result of the operation will have a unit. This only works for multiplication and division.
|
100
|
+
```ruby
|
101
|
+
Quantity.new('50 °F') * 2 = 100 °F
|
102
|
+
Quantity.new('100 °F') / 2 = 50 °F
|
103
|
+
```
|
104
|
+
|
105
|
+
If the operand is a dimensioned NumberItem it will automatically be converted to a quantity for the operation.
|
106
|
+
```ruby
|
107
|
+
# NumberF = '2 °F'
|
108
|
+
# NumberC = '2 °C'
|
109
|
+
|
110
|
+
Quantity.new('50 °F') + NumberF # = 52.0 °F
|
111
|
+
Quantity.new('50 °F') + NumberC # = 85.60 °F
|
112
|
+
```
|
113
|
+
|
114
|
+
If the operand is a non-dimensioned NumberItem it can be used only in multiplication and division operations.
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
# Number Dimensionless = 2
|
118
|
+
|
119
|
+
Quantity.new('50 °F') * Dimensionless # = 100 °F
|
120
|
+
Quantity.new('50 °F') / Dimensionless # = 25 °F
|
121
|
+
```
|
122
|
+
|
123
|
+
Quantities can be compared, if they have comparable units.
|
124
|
+
```ruby
|
125
|
+
Quantity.new('50 °F') > Quantity.new('25 °F')
|
126
|
+
Quantity.new('50 °F') > Quantity.new('525 °F')
|
127
|
+
Quantity.new('50 °F') >= Quantity.new('50 °F')
|
128
|
+
Quantity.new('50 °F') == Quantity.new('50 °F')
|
129
|
+
Quantity.new('50 °F') < Quantity.new('25 °C')
|
130
|
+
```
|
131
|
+
|
132
|
+
If the compare-to is a string, it will be automatically converted into a quantity.
|
133
|
+
```ruby
|
134
|
+
Quantity.new('50 °F') == '50 °F'
|
135
|
+
Quantity.new('50 °F') < '25 °C'
|
136
|
+
```
|
137
|
+
|
138
|
+
Dimensioned Number Items can be converted to quantities with other units using the \| operator
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
# NumberC = '23 °C'
|
142
|
+
|
143
|
+
# Using a unit
|
144
|
+
logger.info("In Fahrenheit #{NumberC| ImperialUnits::FAHRENHEIT }")
|
145
|
+
|
146
|
+
# Using a string
|
147
|
+
logger.info("In Fahrenheit #{NumberC | '°F'}")
|
148
|
+
|
149
|
+
```
|
150
|
+
|
151
|
+
Dimensionless Number Items can be converted to quantities with units using the \| operator
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
# Dimensionless = 70
|
155
|
+
|
156
|
+
# Using a unit
|
157
|
+
logger.info("In Fahrenheit #{Dimensionless| ImperialUnits::FAHRENHEIT }")
|
158
|
+
|
159
|
+
# Using a string
|
160
|
+
logger.info("In Fahrenheit #{Dimensionless | '°F'}")
|
161
|
+
|
162
|
+
```
|
163
|
+
|
164
|
+
Dimensioned Number Items automatically use their units and convert automatically for math operations
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
# Number:Temperature NumberC = 23 °C
|
168
|
+
# Number:Temperature NumberF = 70 °F
|
169
|
+
|
170
|
+
NumberC - NumberF # = 1.88 °C
|
171
|
+
NumberF + NumberC # = 143.40 °F
|
172
|
+
```
|
173
|
+
|
174
|
+
Dimensionless Number Items can be used for multiplication and division.
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
# Number Dimensionless = 2
|
178
|
+
# Number:Temperature NumberF = 70 °F
|
179
|
+
|
180
|
+
NumberF * Dimensionless # = 140.0 °F
|
181
|
+
NumberF / Dimensionless # = 35.0 °F
|
182
|
+
Dimensionless * NumberF # = 140.0 °F
|
183
|
+
2 * NumberF # = 140.0 °F
|
184
|
+
```
|
185
|
+
|
186
|
+
Comparisons work on dimensioned number items with different, but comparable units.
|
187
|
+
```ruby
|
188
|
+
# Number:Temperature NumberC = 23 °C
|
189
|
+
# Number:Temperature NumberF = 70 °F
|
190
|
+
|
191
|
+
NumberC > NumberF # = true
|
192
|
+
```
|
193
|
+
|
194
|
+
Comparisons work with dimensioned numbers and strings representing quantities
|
195
|
+
```ruby
|
196
|
+
# Number:Temperature NumberC = 23 °C
|
197
|
+
# Number:Temperature NumberF = 70 °F
|
198
|
+
|
199
|
+
NumberC > '4 °F' #= true
|
200
|
+
NumberC == '23 °C' #= true
|
201
|
+
```
|
202
|
+
|
203
|
+
For certain unit types, such as temperature, all unit needs to be normalized to the comparator for all operations when combining comparison operators with dimensioned numbers.
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
(NumberC |'°F') - (NumberF |'°F') < '4 °F'
|
207
|
+
```
|
208
|
+
|
209
|
+
To facilitate conversion of multiple dimensioned and dimensionless numbers the unit block may be used. The unit block attempts to do the _right thing_ based on the mix of dimensioned and dimensionless items within the block. Specifically all dimensionless items are converted to the supplied unit, except when they are used for multiplication or division.
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
# Number:Temperature NumberC = 23 °C
|
213
|
+
# Number:Temperature NumberF = 70 °F
|
214
|
+
# Number Dimensionless = 2
|
215
|
+
|
216
|
+
unit('°F') { NumberC - NumberF < 4 } #= true
|
217
|
+
unit('°F') { NumberC - '24 °C' < 4 } #= true
|
218
|
+
unit('°F') { Quantity.new('24 °C') - NumberC < 4 } #= true
|
219
|
+
unit('°C') { NumberF - '20 °C' < 2 } #= true
|
220
|
+
unit('°C') { NumberF - Dimensionless } #= 19.11 °C
|
221
|
+
unit('°C') { NumberF - Dimensionless < 20 } #= true
|
222
|
+
unit('°C') { Dimensionless + NumberC == 25 } #= true unit('°C') { 2 + NumberC == 25 } #= true
|
223
|
+
unit('°C') { Dimensionless * NumberC == 46 } #= true unit('°C') { 2 * NumberC == 46 } #= true
|
224
|
+
unit('°C') { ( (2 * (NumberF + NumberC) ) / Dimensionless ) < 45} #= true unit('°C') { [NumberC, NumberF, Dimensionless].min } #= 2
|
225
|
+
```
|