Skip to content

Commit c7403b6

Browse files
committed
Add ability to exclude / include by manufacturer
Add conversion from m/s to kts
1 parent 4fd58a8 commit c7403b6

4 files changed

Lines changed: 83 additions & 20 deletions

File tree

custom_components/nmea2000/config_flow.py

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,83 @@
22
import voluptuous as vol
33
from homeassistant import config_entries
44
from homeassistant.core import callback
5-
from homeassistant.helpers.selector import SelectSelector, SelectSelectorConfig
5+
from homeassistant.helpers.selector import SelectSelector, SelectSelectorConfig, SelectSelectorMode
66
from homeassistant.const import CONF_NAME
7-
# from homeassistant.exceptions import HomeAssistantError
8-
9-
from .const import CONF_DEVICE_TYPE, CONF_EXPERIMENTAL, DOMAIN, CONF_PGN_INCLUDE, CONF_PGN_EXCLUDE, CONF_PORT, CONF_IP, CONF_BAUDRATE, CONF_MODE, CONF_SERIAL_PORT, CONF_MODE_TCP, CONF_MODE_USB, CONF_MS_BETWEEN_UPDATES, CONF_EXCLUDE_AIS
107
import logging
8+
import homeassistant.helpers.config_validation as cv
9+
10+
from .const import (
11+
CONF_DEVICE_TYPE,
12+
CONF_EXPERIMENTAL,
13+
CONF_MANUFACTURER_CODES_EXCLUDE,
14+
CONF_MANUFACTURER_CODES_INCLUDE,
15+
DOMAIN,
16+
CONF_PGN_INCLUDE,
17+
CONF_PGN_EXCLUDE,
18+
CONF_PORT,
19+
CONF_IP,
20+
CONF_BAUDRATE,
21+
CONF_MODE,
22+
CONF_SERIAL_PORT,
23+
CONF_MODE_TCP,
24+
CONF_MODE_USB,
25+
CONF_MS_BETWEEN_UPDATES,
26+
CONF_EXCLUDE_AIS,
27+
)
1128

1229
_LOGGER = logging.getLogger(__name__)
1330

14-
class NetwrorkDeviceType(Enum):
31+
MANUFACTURER_CODES = [
32+
{"value": "b_and_g", "label": "B & G"},
33+
{"value": "garmin", "label": "Garmin"},
34+
{"value": "mastervolt", "label": "Mastervolt"},
35+
{"value": "victron", "label": "Victron Energy"}
36+
]
37+
38+
class NetworkDeviceType(Enum):
1539
"""Enum for device types."""
1640
EBYTE = "EBYTE"
1741
ACTISENSE = "Actisense"
1842
YACHT_DEVICES = "Yacht Devices"
19-
43+
44+
def get_manufacturer_selector(name: str) -> SelectSelector:
45+
"""Create a manufacturer selector."""
46+
return SelectSelector(
47+
SelectSelectorConfig(
48+
options=MANUFACTURER_CODES,
49+
mode=SelectSelectorMode.DROPDOWN,
50+
multiple=True,
51+
translation_key=name,
52+
)
53+
)
2054

2155
USB_DATA_SCHEMA = vol.Schema(
2256
{
2357
vol.Required(CONF_SERIAL_PORT, default="/dev/ttyUSB0"): str,
2458
vol.Required(CONF_BAUDRATE, default=2000000): int,
2559
vol.Optional(CONF_PGN_INCLUDE): str,
2660
vol.Optional(CONF_PGN_EXCLUDE): str,
27-
vol.Optional(CONF_EXCLUDE_AIS, default=True): bool,
2861
vol.Optional(CONF_MS_BETWEEN_UPDATES, default=5000): int,
62+
vol.Optional(CONF_EXCLUDE_AIS, default=True): bool,
63+
vol.Optional(CONF_MANUFACTURER_CODES_INCLUDE): get_manufacturer_selector(CONF_MANUFACTURER_CODES_INCLUDE),
64+
vol.Optional(CONF_MANUFACTURER_CODES_EXCLUDE): get_manufacturer_selector(CONF_MANUFACTURER_CODES_EXCLUDE),
2965
vol.Optional(CONF_EXPERIMENTAL): bool,
3066
}
3167
)
68+
3269
TCP_DATA_SCHEMA = vol.Schema(
3370
{
34-
vol.Required(CONF_DEVICE_TYPE, default=NetwrorkDeviceType.EBYTE): vol.In([e.value for e in NetwrorkDeviceType]),
71+
vol.Required(CONF_DEVICE_TYPE, default=NetworkDeviceType.EBYTE.value): vol.In(
72+
[e.value for e in NetworkDeviceType]
73+
),
3574
vol.Required(CONF_IP, default="192.168.0.46"): str,
3675
vol.Required(CONF_PORT, default=8881): int,
3776
vol.Optional(CONF_PGN_INCLUDE): str,
3877
vol.Optional(CONF_PGN_EXCLUDE): str,
39-
vol.Optional(CONF_EXCLUDE_AIS, default=True): bool,
4078
vol.Optional(CONF_MS_BETWEEN_UPDATES, default=5000): int,
79+
vol.Optional(CONF_EXCLUDE_AIS, default=True): bool,
80+
vol.Optional(CONF_MANUFACTURER_CODES_INCLUDE): get_manufacturer_selector(CONF_MANUFACTURER_CODES_INCLUDE),
81+
vol.Optional(CONF_MANUFACTURER_CODES_EXCLUDE): get_manufacturer_selector(CONF_MANUFACTURER_CODES_EXCLUDE),
4182
vol.Optional(CONF_EXPERIMENTAL): bool,
4283
}
4384
)
@@ -127,6 +168,9 @@ async def async_step_options(self, user_input=None):
127168
if CONF_PGN_INCLUDE in user_input and CONF_PGN_EXCLUDE in user_input:
128169
errors[CONF_PGN_EXCLUDE] = "include_exclude_only_one"
129170

171+
if len(user_input[CONF_MANUFACTURER_CODES_INCLUDE]) != 0 and len(user_input[CONF_MANUFACTURER_CODES_EXCLUDE]) != 0:
172+
errors[CONF_MANUFACTURER_CODES_EXCLUDE] = "include_exclude_only_one"
173+
130174
if len(errors) == 0:
131175
new_data = self.data | user_input
132176
_LOGGER.debug("No errors. Storing data: %s", new_data)
@@ -178,6 +222,9 @@ async def async_step_init(self, user_input=None):
178222
if CONF_PGN_INCLUDE in user_input and CONF_PGN_EXCLUDE in user_input:
179223
errors[CONF_PGN_EXCLUDE] = "include_exclude_only_one"
180224

225+
if len(user_input[CONF_MANUFACTURER_CODES_INCLUDE]) != 0 and len(user_input[CONF_MANUFACTURER_CODES_EXCLUDE]) != 0:
226+
errors[CONF_MANUFACTURER_CODES_EXCLUDE] = "include_exclude_only_one"
227+
181228
if len(errors) == 0:
182229
new_data = user_input
183230
# merge back the name and mode which are missing from this page

custom_components/nmea2000/const.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@
1212
CONF_MS_BETWEEN_UPDATES = "ms_between_updates"
1313
CONF_EXCLUDE_AIS = "exclude_AIS"
1414
CONF_DEVICE_TYPE = "device_type"
15-
CONF_EXPERIMENTAL = "experimental"
15+
CONF_EXPERIMENTAL = "experimental"
16+
CONF_MANUFACTURER_CODES_INCLUDE = "manufacturer_codes_include"
17+
CONF_MANUFACTURER_CODES_EXCLUDE = "manufacturer_codes_exclude"

custom_components/nmea2000/hub.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
CONF_DEVICE_TYPE,
2020
CONF_EXCLUDE_AIS,
2121
CONF_EXPERIMENTAL,
22+
CONF_MANUFACTURER_CODES_EXCLUDE,
23+
CONF_MANUFACTURER_CODES_INCLUDE,
2224
CONF_MODE,
2325
CONF_PGN_INCLUDE,
2426
CONF_PGN_EXCLUDE,
@@ -29,7 +31,7 @@
2931
CONF_PORT,
3032
CONF_MS_BETWEEN_UPDATES,
3133
)
32-
from .config_flow import NetwrorkDeviceType, parse_and_validate_comma_separated_integers
34+
from .config_flow import NetworkDeviceType, parse_and_validate_comma_separated_integers
3335
from .NMEA2000Sensor import NMEA2000Sensor
3436

3537
# Home Assistant imports
@@ -122,18 +124,22 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
122124
# remove duplicates
123125
pgn_include = list(set(pgn_include))
124126
pgn_exclude = list(set(pgn_exclude))
127+
include_manufacturer_code = entry.data.get(CONF_MANUFACTURER_CODES_INCLUDE, [])
128+
exclude_manufacturer_code = entry.data.get(CONF_MANUFACTURER_CODES_EXCLUDE, [])
125129

126-
preferred_units = {PhysicalQuantities.TEMPERATURE:"C", PhysicalQuantities.ANGLE:"deg"}
130+
preferred_units = {PhysicalQuantities.TEMPERATURE:"C", PhysicalQuantities.ANGLE:"deg", PhysicalQuantities.SPEED:"kts"}
127131

128132
_LOGGER.info(
129-
"Configuring sensor with name: %s, mode: %s, PGN Include: %s, PGN Exclude: %s, preferred_units: %s, dump_to_file: %s, dump_pgns: %s",
133+
"Configuring sensor with name: %s, mode: %s, PGN Include: %s, PGN Exclude: %s, preferred_units: %s, dump_to_file: %s, dump_pgns: %s, include_manufacturer_code: %s, exclude_manufacturer_code: %s",
130134
self.name,
131135
mode,
132136
pgn_include,
133137
pgn_exclude,
134138
preferred_units,
135139
dump_to_file,
136-
dump_pgns
140+
dump_pgns,
141+
include_manufacturer_code,
142+
exclude_manufacturer_code,
137143
)
138144

139145
# Create system sensors
@@ -177,19 +183,21 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
177183
dump_to_file=dump_to_file,
178184
dump_pgns=dump_pgns,
179185
build_network_map = build_network_map,
186+
include_manufacturer_code = include_manufacturer_code,
187+
exclude_manufacturer_code = exclude_manufacturer_code,
180188
)
181189
elif mode == "TCP":
182190
ip = entry.data[CONF_IP]
183191
port = entry.data[CONF_PORT]
184-
device_type = NetwrorkDeviceType(entry.data[CONF_DEVICE_TYPE])
192+
device_type = NetworkDeviceType(entry.data[CONF_DEVICE_TYPE])
185193
_LOGGER.info(
186194
"TCP sensor with name: %s, IP: %s, port: %s, device_type: %s",
187195
self.name,
188196
ip,
189197
port,
190198
device_type
191199
)
192-
if device_type == NetwrorkDeviceType.EBYTE:
200+
if device_type == NetworkDeviceType.EBYTE:
193201
self.gateway = EByteNmea2000Gateway(
194202
host=ip,
195203
port=port,
@@ -199,8 +207,10 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
199207
dump_to_file=dump_to_file,
200208
dump_pgns=dump_pgns,
201209
build_network_map = build_network_map,
210+
include_manufacturer_code = include_manufacturer_code,
211+
exclude_manufacturer_code = exclude_manufacturer_code,
202212
)
203-
elif device_type == NetwrorkDeviceType.ACTISENSE:
213+
elif device_type == NetworkDeviceType.ACTISENSE:
204214
self.gateway = ActisenseNmea2000Gateway(
205215
host=ip,
206216
port=port,
@@ -210,8 +220,10 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
210220
dump_to_file=dump_to_file,
211221
dump_pgns=dump_pgns,
212222
build_network_map = build_network_map,
223+
include_manufacturer_code = include_manufacturer_code,
224+
exclude_manufacturer_code = exclude_manufacturer_code,
213225
)
214-
elif device_type == NetwrorkDeviceType.YACHT_DEVICES:
226+
elif device_type == NetworkDeviceType.YACHT_DEVICES:
215227
self.gateway = YachtDevicesNmea2000Gateway(
216228
host=ip,
217229
port=port,
@@ -221,6 +233,8 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
221233
dump_to_file=dump_to_file,
222234
dump_pgns=dump_pgns,
223235
build_network_map = build_network_map,
236+
include_manufacturer_code = include_manufacturer_code,
237+
exclude_manufacturer_code = exclude_manufacturer_code,
224238
)
225239
else:
226240
raise Exception(f"device_type {device_type} not supported")

custom_components/nmea2000/manifest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"iot_class": "local_push",
1212
"issue_tracker": "https://github.com/tomer-w/ha-nmea2000/issues",
1313
"requirements": [
14-
"nmea2000==2025.5.18"
14+
"nmea2000==2025.6.3"
1515
],
16-
"version": "2025.6.1"
16+
"version": "2025.6.2"
1717
}

0 commit comments

Comments
 (0)