-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[airvisualnode] Initial contribution for AirVisual Node Binding #2805
Conversation
d847482
to
c74701e
Compare
<description>Node network password</description> | ||
</parameter> | ||
<!-- Advanced parameters --> | ||
<parameter name="share" type="text"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation went wrong. Spaces instead of tabs used?
| Channel ID | Item Type | Description | | ||
|------------------------------|-----------|-----------------------------| | ||
| measurements#co2_ppm | Number | CO₂ level, ppm | | ||
| measurements#humidity | Number | Humidity, % | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation of last bar | (also same with last entries of this table).
<p>March 30, 2017</p> | ||
<h3>License</h3> | ||
|
||
<p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thing you need to add a Third Party Content
section here regarding the license of the lib cifs in this file.
|
||
schedulePoll(); | ||
|
||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Node poll scheduled"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will always hide the 2 previous configuration errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since you added the return
statements above you will always end up with an offline thing which in reality is still in INITIALIZING
state, I would suggest to remove this line and set the thing to ONLINE or OFFLINE inside your polling job.
|
||
this.refreshInterval = config.refresh * 1000L; | ||
|
||
schedulePoll(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to start the polling when there is a configuration error?
String url = "smb://" + nodeAddress +"/" + nodeShareName + "/" + NODE_JSON_FILE; | ||
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(null, nodeUsername, nodePassword); | ||
try (SmbFileInputStream in = new SmbFileInputStream(new SmbFile(url, auth))) { | ||
return IOUtils.toString(new SmbFileInputStream(new SmbFile(url, auth)), StandardCharsets.UTF_8.name()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably ment to use the variable in
here that you moved to the line above.
@Override | ||
protected void startBackgroundDiscovery() { | ||
logger.debug("Starting background discovery"); | ||
cancelBackgroundDiscoveryFuture(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume stop is always called before start so there is probably no need to call this cancel?
@Override | ||
protected void startScan() { | ||
logger.debug("Starting scan"); | ||
scheduler.execute(scannerRunnable); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe rewrite this as: scheduler.execute(this::createScannerRunnable());
and remove the return part from createScannerRunnable()
? (Although then the method name probably should be something more related to the running itself instead of creating the runnable`)
String workgroupUrl = "smb://" + AVISUAL_WORKGROUP_NAME +"/"; | ||
workgroupMembers = new SmbFile(workgroupUrl).listFiles(); | ||
} catch (Exception e) { | ||
// Can't get workgroup member list |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure it's not needed to log here? These exceptions will go undetected and might hide bugs.
| status#used_memory | Number | Used memory | | ||
| status#timestamp | DateTime | Timestamp | | ||
|
||
## Example |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can also use an example of a Thing with parameter configuration.
Thank you very much @Hilbrand for prompt PR reviewing, I'll fix that. |
4f1d2d8
to
949f0da
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much for your contribution. And sorry that it took so long until you got another (more-detailed) review.
The overall code looks pretty good, except for that you should get rid of the channel groups.
Please have a look at my comments in the code.
If you have any questions, feel free to ask!
## Discovery | ||
|
||
Binding will do autodiscovery for AirVisual Node by searching for a host advertised with the NetBIOS name 'AVISUAL-<SerialNumber>'. | ||
All discovered devices will be added to the inbox. Please note you will need to set the Node username and password in the configuration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a line break after each sentence, this makes merging a lot easier afterwards.
|
||
## Channels | ||
|
||
The binding support the following channels: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
supports
| measurements#aqi_us | Number | Air Quality Index (US) | | ||
| measurements#pm_25 | Number | PM2.5 level, μg/m³ | | ||
| measurements#temp_celsius | Number | Temperature, Celsius | | ||
| measurements#temp_fahrenheit | Number | Temperature, Fahrenheit | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since a few weeks we have a great new feature called units of measurement which would be a great fit for your binding. You can specify your channels with the correct unit and transformations will be done automatically by the framework. Please have a look at it.
|
||
| Channel ID | Item Type | Description | | ||
|------------------------------|-----------|-----------------------------| | ||
| status#battery_level | Number | Battery level, % | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do have a system channel
available for this, please make use of it. System channels are for harmonizing the way multiple bindings provide their information. See https://www.eclipse.org/smarthome/documentation/development/bindings/thing-definition.html#channels
| Channel ID | Item Type | Description | | ||
|------------------------------|-----------|-----------------------------| | ||
| status#battery_level | Number | Battery level, % | | ||
| status#wifi_strength | Number | Wi-Fi signal strength | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do have a system channel
available for this, please make use of it. System channels are for harmonizing the way multiple bindings provide their information. See https://www.eclipse.org/smarthome/documentation/development/bindings/thing-definition.html#channels
<label>Status</label> | ||
<channels> | ||
<channel id="battery_level" typeId="system.battery-level" /> | ||
<channel id="wifi_strength" typeId="system.signal-strength" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comment below, use a system channel for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, could you clarify please, do you mean I should change these channel ids? Because both channels are already referenced to a system channel typeIds. Should I just rename channel ids to battery-level
and signal-strength
, or some more changes are required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upps, sorry apparently I stopped reading after <channel id="battery_level"
... Sorry my fault.
Object value = null; | ||
|
||
if (nodeData != null) { | ||
String[] fullChannelIdFields = StringUtils.split(fullChannelId, "#"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not understand why you have to split the channelID by #
. You should pass the correct ID to this method instead, splitting at #
is not reliable.
@Override | ||
protected void startBackgroundDiscovery() { | ||
logger.debug("Starting background discovery"); | ||
backgroundDiscoveryFuture = scheduler.scheduleWithFixedDelay(this::scan, 0, 300, TimeUnit.SECONDS); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure that the library you are using is doing the scan in the same way as windows clients do it? Because if you do a periodic scan every 5 minutes of the whole network your machine could be subject to be blocked by a net intrusion system in certain network setups. So I am unsure whether we should keep the automatic scan without user interaction in here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the discovery process just requests SMB servers list from the local master browser using JCIFS library. Not sure how this operation will be treated by a net intrusion systems if repeated though. Do you recommend to disable periodic autodiscovery here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am no 100% sure. I just have in mind that we do not want discovery processes to "flood" the network without a user-interaction. A background scan works without a user interaction. If you would move it to startScan
the user has to initiate the scan. But in your scenario is a corner case I guess and I am not a windows expert. Querying the master browser for the list of servers every 5min doesn't sound too bad though. Let's leave it in for now, I just wanted to understand what is actually happening here.
try { | ||
String workgroupUrl = "smb://" + AVISUAL_WORKGROUP_NAME +"/"; | ||
workgroupMembers = new SmbFile(workgroupUrl).listFiles(); | ||
} catch (Exception e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above, please do not catch Exception
// Create discovery result | ||
String nodeAddress = nodeNbtAddress.getInetAddress().getHostAddress(); | ||
DiscoveryResult result = DiscoveryResultBuilder.create(thingUID) | ||
.withProperty(AirVisualNodeConfig.ADDRESS, nodeAddress) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is also unique for all devices, you should make it a representationProperty
, see https://www.eclipse.org/smarthome/documentation/development/bindings/discovery-services.html
Hello @triller-telekom, thank you for reviewing this PR! Got some questions about applying UOM to the Air quality index (AQI). AQI US and AQI CN values are both dimensionless and differs only by method used for their computation (please see corresponding Wikipedia article if you're interested). Is the UOM still applicable in this case? |
Hi @3cky, regarding AQI I suggest not to use UOM in this case. AQI is a scale which maps to a combination of quantitative measurements. Its is itself not a quantitative property. You could use |
949f0da
to
2ed89b2
Compare
Hello @triller-telekom @htreu, Thanks for your assistance! I've pushed updated PR, now UoM are used by all Node measurement channels. Not quite sure about the PM2.5 avnode.rules:
openhab.log:
Is this expected behaviour? |
@3cky unfortunately right now this is expected. The unit symbols |
Addresses https://github.com/openhab/openhab2-addons/pull/2805#issuecomment-388782058. Signed-off-by: Henning Treu <henning.treu@telekom.de>
@3cky once eclipse-archived/smarthome#5574 is merged and available for openHAB your scripts should work as expected. |
Hi @htreu, Great! I'll wait for it, thank you! |
Addresses https://github.com/openhab/openhab2-addons/pull/2805#issuecomment-388782058. Signed-off-by: Henning Treu <henning.treu@telekom.de>
@3cky the corresponding PR already got merged and a new Eclipse SmartHome stable build also is available: DISCLAIMER: it introduced a new bug when triggering rules, so while µ and ^2/^3 are available it might nonetheless break your rule. |
Hello @htreu, probably I did miss something but I still expiriencing the very same error ("no viable alternative at input" etc) in OpenHAB 2.3.0-SNAPSHOT build 1284. |
Please note that unit support in scripts had to be refactored just recently. It now uses |
I've tried this rule in openHAB 2.4.0-SNAPSHOT build 1299:
and I'm still getting the error:
|
Update: I've changed
|
I can for now confirm this issue. Testing with |
Here are my findings about this:
Please try a script like I'm not sure why and when a keyboard input produces which character. On my mac OS the combination |
Wow, not that is really nasty! @keilw, are you aware of this? What's the suggested UoM way to deal with it? |
@htreu Any explanation why you found |
Have to check, but I know when I created JUnit tests for the temperature question, it occurred to me again, there are 2 ways to render |
We know, we just got rid off that "feature"... eclipse-archived/smarthome#5669 |
When I author the unit test with my setup everything works as expected. After @3cky's last report I did copy his script from the comment and reproduced the error. All |
There are other formatters/parsers, especially in the UCUM bundle, but that would have to be used via CQ. |
As for the visual differences: I can only see it on the external HD screen. On the MacBook retina screen it makes zero to none difference. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for addressing the review commits.
I had a look at them and except for a few minor issues they look good to me. Please have a look at my comments in the code.
<description>Air Quality Index (US)</description> | ||
<category>Flow</category> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if this is the right category. What is flowing here? Better leave it out.
<label>PM2.5</label> | ||
<description>PM2.5 level, μg/m³</description> | ||
<state readOnly="true" pattern="%.1f μg/m³" /> | ||
<category>Flow</category> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if this is the right category. What is flowing here? Better leave it out.
org.eclipse.smarthome.core.thing.binding.builder, | ||
org.eclipse.smarthome.core.thing.type, | ||
org.eclipse.smarthome.core.types, | ||
org.osgi.service.component.annotations;resolution:=optional, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please incorporate my comment and remove this line. It is not needed.
Number:Dimensionless Livingroom_Humidity "Humidity [%d %unit%]" <humidity> {channel="airvisualnode:avnode:1a2b3c4:humidity"} | ||
Number:Dimensionless Livingroom_CO2_Level "CO₂" <flow> {channel="airvisualnode:avnode:1a2b3c4:co2"} | ||
Number:Dimensionless Livingroom_Aqi_Level "Air Quality Index" <flow> { channel="airvisualnode:avnode:1a2b3c4:aqi" } | ||
Number:Density Livingroom_Pm25_Level "PM2.5 Level" <line> { channel="airvisualnode:avnode:1a2b3c4:pm_25" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where do you have the category "line" from? I cannot find it in our documentation: https://www.eclipse.org/smarthome/documentation/concepts/categories.html
Number:Dimensionless Livingroom_CO2_Level "CO₂" <flow> {channel="airvisualnode:avnode:1a2b3c4:co2"} | ||
Number:Dimensionless Livingroom_Aqi_Level "Air Quality Index" <flow> { channel="airvisualnode:avnode:1a2b3c4:aqi" } | ||
Number:Density Livingroom_Pm25_Level "PM2.5 Level" <line> { channel="airvisualnode:avnode:1a2b3c4:pm_25" } | ||
DateTime Livingroom_Aqi_Timestamp "AQI Timestamp [%1$tH:%1$tM]" <clock> { channel="airvisualnode:avnode:1a2b3c4:timestamp" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where do you have the category "clock" from? I cannot find it in our documentation: https://www.eclipse.org/smarthome/documentation/concepts/categories.html
public static final String CHANNEL_BATTERY_LEVEL = "battery_level"; | ||
public static final String CHANNEL_WIFI_STRENGTH = "wifi_strength"; | ||
public static final String CHANNEL_WIFI_STRENGTH = "signal_strength"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you now use the system channels, its probably better to use their definitions directly, i.e.: DefaultSystemChannelTypeProvider.SYSTEM_SYSTEM_CHANNEL_SIGNAL_STRENGTH.getUID().getId()
Same applies to other system channels of course.
f0ba894
to
9840120
Compare
Hello @triller-telekom, Thank you for reviewing this PR and please sorry for my late response. I removed problematic item categories, cleaned up MANIFEST.MF from all non-essential import packages and did changes in system channels handling code. Please let me know if there are any other fixes needed. |
Thank you for the changes. Looks good, except that you missed on of my comments: https://github.com/openhab/openhab2-addons/pull/2805#discussion_r199102470 |
@triller-telekom do you mean this line? Is this normal or I did miss something? |
@3cky Are you using the official openHAB IDE? If not, you will need to enable the DS annotation generator, I just commented this on eclipse-archived/smarthome#5954 (comment). |
@kaikreuzer you're right, I'm using not openHAB IDE but regular Eclipse IDE installation. I followed your instructions and error is gone now. Thanks! So I'll remove annotations package import from the manifest file. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much for the binding and all the incorporated changes.
I leave it to @kaikreuzer and @martinvw to have a look and merge the binding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks great indeed, I added some minor comments, I will also queue you up at @kaikreuzer
</buildCommand> | ||
</buildSpec> | ||
<natures> | ||
<nature>org.eclipse.m2e.core.maven2Nature</nature> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not be here?
.getUID().getId(); | ||
|
||
// List of all supported Thing UIDs | ||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Afair, Set
's should be annotated to have a nullable generic, because otherwise the compiler might assume that a set cannot return null but it can.
@maggu2810 or am I mistaken now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@martinvw You are right, but where is that @Nullable
annotation that you are referring to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing and the class is annotated to be not Null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah now I understand my misunderstanding of your comment...
Set
s should not be annotated to have a @Nullable
generic, because that would express that we allow to add null
to the collection.
The problem you are mentioning is that a get(item)
on a Set
might always return null
if the requested item
is not in the Set
. But that should be covered by external annotations which annotate (in this case) the JDT. But we do not have them, both PRs eclipse-archived/smarthome#4513 and eclipse-archived/smarthome#4217 were closed.
Long story short: The line here is correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing to add to @triller-telekom's explanation. 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great thanks guys!
|
||
public AirVisualNodeHandler(Thing thing) { | ||
super(thing); | ||
gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
} | ||
|
||
private String getNodeJsonData() throws IOException { | ||
String url = "smb://" + nodeAddress +"/" + nodeShareName + "/" + NODE_JSON_FILE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very small formatting error, if in doubt format all your (Java) files
case CHANNEL_TIMESTAMP: | ||
// It seem the Node timestamp is Unix timestamp converted from UTC time plus timezone offset. | ||
// Not sure about DST though, but it's best guess at now | ||
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have more modern options since Java 8, I would prefer if you use them instead of the calendar
@Override | ||
protected void startBackgroundDiscovery() { | ||
logger.debug("Starting background discovery"); | ||
backgroundDiscoveryFuture = scheduler.scheduleWithFixedDelay(this::scan, 0, 300, TimeUnit.SECONDS); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not specify the much more explicit
..., 0, 5, TimeUnit.MINUTES);
Hello @martinvw, thank you for your comments! I did some fixes, please check them out. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Many thanks, this looks wonderful!
Just some very minor last comments before merging, see below.
<config-description> | ||
<!-- Required parameters --> | ||
<parameter name="address" type="text" required="true"> | ||
<context>network_address</context> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be network-address
.
<state readOnly="true" /> | ||
</channel-type> | ||
|
||
<channel-type id="Used_memory"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like a good candidate to mark as advanced=true.
|
||
## Supported Things | ||
|
||
There is one supported Thing, the "AirVisual Node". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should mention its ID here.
@3cky Please ping me once you have pushed an update - thanks! |
Signed-off-by: Victor Antonovich <v.antonovich@gmail.com> (github: 3cky)
Signed-off-by: Victor Antonovich <v.antonovich@gmail.com>
Signed-off-by: Victor Antonovich <v.antonovich@gmail.com>
Signed-off-by: Victor Antonovich <v.antonovich@gmail.com>
Signed-off-by: Victor Antonovich <v.antonovich@gmail.com>
Signed-off-by: Victor Antonovich <v.antonovich@gmail.com>
Signed-off-by: Victor Antonovich <v.antonovich@gmail.com>
Signed-off-by: Victor Antonovich <v.antonovich@gmail.com>
Signed-off-by: Victor Antonovich <v.antonovich@gmail.com>
a88f7b5
to
d63e3eb
Compare
Hello @kaikreuzer, thank you for your patience. I made fixes in accordance with your comments, please check. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thanks a lot!
Great, thank you all guys for your assistance! |
…hab#2805) Signed-off-by: Victor Antonovich <v.antonovich@gmail.com> (github: 3cky)
This binding integrates AirVisual Node Air Quality Monitor with openHAB.
For complete information about this binding, please check Readme.md.
Signed-off-by: Victor Antonovich v.antonovich@gmail.com