diff --git a/esphome/const.py b/esphome/const.py
index f33b4ee406..35d4b016ce 100644
--- a/esphome/const.py
+++ b/esphome/const.py
@@ -10,7 +10,8 @@ ESP_PLATFORM_ESP32 = "ESP32"
ESP_PLATFORM_ESP8266 = "ESP8266"
ESP_PLATFORMS = [ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266]
-ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789_-"
+ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
+
# Lookup table from ESP32 arduino framework version to latest platformio
# package with that version
# See also https://github.com/platformio/platform-espressif32/releases
diff --git a/esphome/dashboard/static/js/esphome.js b/esphome/dashboard/static/js/esphome.js
index 52dda446ce..e861f169df 100644
--- a/esphome/dashboard/static/js/esphome.js
+++ b/esphome/dashboard/static/js/esphome.js
@@ -1012,6 +1012,10 @@ jQuery.validator.addMethod("nospaces", (value, element) => {
return value.indexOf(' ') < 0;
}, "Name cannot contain any spaces!");
+jQuery.validator.addMethod("nounderscores", (value, element) => {
+ return value.indexOf('_') < 0;
+}, "Name cannot contain underscores!");
+
jQuery.validator.addMethod("lowercase", (value, element) => {
return value === value.toLowerCase();
}, "Name must be all lower case!");
diff --git a/esphome/dashboard/templates/index.html b/esphome/dashboard/templates/index.html
index 142bc2cd6f..dee10bfc27 100644
--- a/esphome/dashboard/templates/index.html
+++ b/esphome/dashboard/templates/index.html
@@ -359,12 +359,12 @@
Names must be all lowercase and must not contain any spaces!
Characters that are allowed are: a-z
,
- 0-9
, _
and -
.
+ 0-9
and -
.
+ data-rule-lowercase="true" data-rule-nounderscores="true" required>
diff --git a/esphome/wizard.py b/esphome/wizard.py
index 4ad5c63216..3550e39392 100644
--- a/esphome/wizard.py
+++ b/esphome/wizard.py
@@ -196,11 +196,11 @@ def wizard(path):
color(
Fore.RED,
f'Oh noes, "{name}" isn\'t a valid name. Names can only '
- f"include numbers, lower-case letters, underscores and "
- f"hyphens.",
+ f"include numbers, lower-case letters and hyphens. ",
)
)
- name = strip_accents(name).lower().replace(" ", "_")
+ name = strip_accents(name).lower().replace(" ", "-")
+ name = strip_accents(name).lower().replace("_", "-")
name = "".join(c for c in name if c in ALLOWED_NAME_CHARS)
safe_print(
'Shall I use "{}" as the name instead?'.format(color(Fore.CYAN, name))
diff --git a/tests/unit_tests/test_config_validation.py b/tests/unit_tests/test_config_validation.py
index 949d4251ee..16cfb16e94 100644
--- a/tests/unit_tests/test_config_validation.py
+++ b/tests/unit_tests/test_config_validation.py
@@ -27,7 +27,7 @@ def test_alphanumeric__invalid(value):
config_validation.alphanumeric(value)
-@given(value=text(alphabet=string.ascii_lowercase + string.digits + "_-"))
+@given(value=text(alphabet=string.ascii_lowercase + string.digits + "-_"))
def test_valid_name__valid(value):
actual = config_validation.valid_name(value)
diff --git a/tests/unit_tests/test_wizard.py b/tests/unit_tests/test_wizard.py
index 6c952608d4..0ca7c83e1b 100644
--- a/tests/unit_tests/test_wizard.py
+++ b/tests/unit_tests/test_wizard.py
@@ -9,7 +9,7 @@ from mock import MagicMock
@pytest.fixture
def default_config():
return {
- "name": "test_name",
+ "name": "test-name",
"platform": "test_platform",
"board": "test_board",
"ssid": "test_ssid",
@@ -21,7 +21,7 @@ def default_config():
@pytest.fixture
def wizard_answers():
return [
- "test_node", # Name of the node
+ "test-node", # Name of the node
"ESP8266", # platform
"nodemcuv2", # board
"SSID", # ssid
@@ -305,13 +305,14 @@ def test_wizard_offers_better_node_name(tmpdir, monkeypatch, wizard_answers):
"""
When the node name does not conform, a better alternative is offered
* Removes special chars
- * Replaces spaces with underscores
+ * Replaces spaces with hyphens
+ * Replaces underscores with hyphens
* Converts all uppercase letters to lowercase
"""
# Given
- wizard_answers[0] = "Küche #2"
- expected_name = "kuche_2"
+ wizard_answers[0] = "Küche_Unten #2"
+ expected_name = "kuche-unten-2"
monkeypatch.setattr(
wz, "default_input", MagicMock(side_effect=lambda _, default: default)
)