Repository: AppDaemon/appdaemon

Issue:
SSL: CERTIFICATE_VERIFY_FAILED
Hi, 

I don't know if you got notified about my last comment in the closed issue #81 . I cannot reopen it, so ill try it this way:

Sorry, I hadn't had the time to test it.
I have tested it now with the newest version 3.0.0b5 and HASS 0.64.3
self.get_state() works now without any problems.

When setting/updating a state (with self.set_state() or self.call_service()) I still receive the following error:

```
Exception in thread Thread-16:
Traceback (most recent call last):
  File "/home/pi/.local/lib/python3.5/site-packages/urllib3/connectionpool.py", line 601, in urlopen
    chunked=chunked)
  File "/home/pi/.local/lib/python3.5/site-packages/urllib3/connectionpool.py", line 346, in _make_request
    self._validate_conn(conn)
  File "/home/pi/.local/lib/python3.5/site-packages/urllib3/connectionpool.py", line 850, in _validate_conn
    conn.connect()
  File "/home/pi/.local/lib/python3.5/site-packages/urllib3/connection.py", line 326, in connect
    ssl_context=context)
  File "/home/pi/.local/lib/python3.5/site-packages/urllib3/util/ssl_.py", line 329, in ssl_wrap_socket
    return context.wrap_socket(sock, server_hostname=server_hostname)
  File "/usr/lib/python3.5/ssl.py", line 385, in wrap_socket
    _context=self)
  File "/usr/lib/python3.5/ssl.py", line 760, in __init__
    self.do_handshake()
  File "/usr/lib/python3.5/ssl.py", line 996, in do_handshake
    self._sslobj.do_handshake()
  File "/usr/lib/python3.5/ssl.py", line 641, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:720)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pi/.local/lib/python3.5/site-packages/requests/adapters.py", line 440, in send
    timeout=timeout
  File "/home/pi/.local/lib/python3.5/site-packages/urllib3/connectionpool.py", line 639, in urlopen
    _stacktrace=sys.exc_info()[2])
  File "/home/pi/.local/lib/python3.5/site-packages/urllib3/util/retry.py", line 388, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='hass.home.local', port=8123): Max retries exceeded with url: /api/services/input_number/set_value (Caused by SSLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:720)'),))
```

My AppDaemon config is:
```
appdaemon:
  threads: 10
  app_dir: '/srv/apps'
  plugins:
    HASS:
      type: hass
      ha_url: 'https://hass.home.local:8123'
      ha_key: 'ABC'
      cert_path: '/etc/ssl/certs/ca-certificates.crt'
      cert_verify: False
```


Setting a state with curl works without any problem.
`curl -X POST -H "x-ha-access: ABC" -H "Content-Type: application/json" -d '{"attributes": {"friendly_name": "Volume", "icon": "mdi:volume-medium", "max": -20.0, "min": -100.0, "mode": "slider", "step": 0.5}, "entity_id": "input_number.volume", "state": "-30.0"}' "https://hass.home.local:8123/api/states/input_number.volume"`


Discussion:
I'm pretty sure that this is failing because the HASS plugin doesn't pay attention to the cert_verify setting when it's using websockets to connect to Home Assistant

Resolving patch:
diff --git a/appdaemon/plugins/hass/hassapi.py b/appdaemon/plugins/hass/hassapi.py
--- a/appdaemon/plugins/hass/hassapi.py
+++ b/appdaemon/plugins/hass/hassapi.py
@@ -119,10 +119,10 @@ def set_state(self, entity_id, **kwargs):
             new_state["attributes"].update(kwargs["attributes"])
 
         config = self.AD.get_plugin(self._get_namespace(**kwargs)).config
-        if "certpath" in config:
-            certpath = config["certpath"]
+        if "cert_path" in config:
+            cert_path = config["cert_path"]
         else:
-            certpath = None
+            cert_path = None
 
         if "ha_key" in config and config["ha_key"] != "":
             headers = {'x-ha-access': config["ha_key"]}
@@ -131,7 +131,7 @@ def set_state(self, entity_id, **kwargs):
         apiurl = "{}/api/states/{}".format(config["ha_url"], entity_id)
 
         r = requests.post(
-            apiurl, headers=headers, json=new_state, verify=certpath
+            apiurl, headers=headers, json=new_state, verify=cert_path
         )
         r.raise_for_status()
         state = r.json()
@@ -337,7 +337,7 @@ def turn_off(self, entity_id, **kwargs):
         else:
             rargs = kwargs
             rargs["entity_id"] = entity_id
-        
+
         device, entity = self.split_entity(entity_id)
         if device == "scene":
             self.call_service("homeassistant/turn_on", **rargs)
@@ -419,17 +419,17 @@ def fire_event(self, event, **kwargs):
         self.AD.log("DEBUG",
                   "fire_event: {}, {}".format(event, kwargs))
         config = self.AD.get_plugin(self._get_namespace(**kwargs)).config
-        if "certpath" in config:
-            certpath = config["certpath"]
+        if "cert_path" in config:
+            cert_path = config["cert_path"]
         else:
-            certpath = None
+            cert_path = None
         if "ha_key" in config and config["ha_key"] != "":
             headers = {'x-ha-access': config["ha_key"]}
         else:
             headers = {}
         apiurl = "{}/api/events/{}".format(config["ha_url"], event)
         r = requests.post(
-            apiurl, headers=headers, json=kwargs, verify=certpath
+            apiurl, headers=headers, json=kwargs, verify=cert_path
         )
         r.raise_for_status()
         return r.json()
@@ -452,10 +452,10 @@ def call_service(self, service, **kwargs):
         )
 
         config = self.AD.get_plugin(self._get_namespace(**kwargs)).config
-        if "certpath" in config:
-            certpath = config["certpath"]
+        if "cert_path" in config:
+            cert_path = config["cert_path"]
         else:
-            certpath = None
+            cert_path = None
 
         if "ha_key" in config and config["ha_key"] != "":
             headers = {'x-ha-access': config["ha_key"]}
@@ -463,7 +463,7 @@ def call_service(self, service, **kwargs):
             headers = {}
         apiurl = "{}/api/services/{}/{}".format(config["ha_url"], d, s)
         r = requests.post(
-            apiurl, headers=headers, json=kwargs, verify=certpath
+            apiurl, headers=headers, json=kwargs, verify=cert_path
         )
         r.raise_for_status()
         return r.json()


Test patch: