Axis - improved internal parameter handling
diff --git a/homeassistant/components/axis/__init__.py b/homeassistant/components/axis/__init__.py
index 7d9cabd09fa3c3..e9e8a158a3be38 100644
--- a/homeassistant/components/axis/__init__.py
+++ b/homeassistant/components/axis/__init__.py
@@ -64,12 +64,9 @@ async def async_unload_entry(hass, config_entry):
 
 async def async_populate_options(hass, config_entry):
     """Populate default options for device."""
-    from axis.vapix import VAPIX_IMAGE_FORMAT
-
     device = await get_device(hass, config_entry.data[CONF_DEVICE])
 
-    supported_formats = device.vapix.get_param(VAPIX_IMAGE_FORMAT)
-
+    supported_formats = device.vapix.params.image_format
     camera = bool(supported_formats)
 
     options = {
diff --git a/homeassistant/components/axis/config_flow.py b/homeassistant/components/axis/config_flow.py
index 54d93f768d20a9..0c175de20c76b1 100644
--- a/homeassistant/components/axis/config_flow.py
+++ b/homeassistant/components/axis/config_flow.py
@@ -66,7 +66,6 @@ async def async_step_user(self, user_input=None):
 
         Manage device specific parameters.
         """
-        from axis.vapix import VAPIX_MODEL_ID, VAPIX_SERIAL_NUMBER
         errors = {}
 
         if user_input is not None:
@@ -79,13 +78,12 @@ async def async_step_user(self, user_input=None):
                 }
                 device = await get_device(self.hass, self.device_config)
 
-                self.serial_number = device.vapix.get_param(
-                    VAPIX_SERIAL_NUMBER)
+                self.serial_number = device.vapix.params.system_serialnumber
 
                 if self.serial_number in configured_devices(self.hass):
                     raise AlreadyConfigured
 
-                self.model = device.vapix.get_param(VAPIX_MODEL_ID)
+                self.model = device.vapix.params.prodnbr
 
                 return await self._create_entry()
 
diff --git a/homeassistant/components/axis/device.py b/homeassistant/components/axis/device.py
index 155d1c4760875f..48577799a1330d 100644
--- a/homeassistant/components/axis/device.py
+++ b/homeassistant/components/axis/device.py
@@ -67,13 +67,9 @@ async def async_update_device_registry(self):
 
     async def async_setup(self):
         """Set up the device."""
-        from axis.vapix import VAPIX_FW_VERSION, VAPIX_PROD_TYPE
-
-        hass = self.hass
-
         try:
             self.api = await get_device(
-                hass, self.config_entry.data[CONF_DEVICE])
+                self.hass, self.config_entry.data[CONF_DEVICE])
 
         except CannotConnect:
             raise ConfigEntryNotReady
@@ -83,8 +79,8 @@ async def async_setup(self):
                 'Unknown error connecting with Axis device on %s', self.host)
             return False
 
-        self.fw_version = self.api.vapix.get_param(VAPIX_FW_VERSION)
-        self.product_type = self.api.vapix.get_param(VAPIX_PROD_TYPE)
+        self.fw_version = self.api.vapix.params.firmware_version
+        self.product_type = self.api.vapix.params.prodtype
 
         if self.config_entry.options[CONF_CAMERA]:
             self.hass.async_create_task(
@@ -188,9 +184,14 @@ async def get_device(hass, config):
         password=config[CONF_PASSWORD],
         port=config[CONF_PORT], web_proto='http')
 
+    device.vapix.initialize_params(preload_data=False)
+
     try:
         with async_timeout.timeout(15):
-            await hass.async_add_executor_job(device.vapix.load_params)
+            await hass.async_add_executor_job(
+                device.vapix.params.update_brand)
+            await hass.async_add_executor_job(
+                device.vapix.params.update_properties)
         return device
 
     except axis.Unauthorized:
diff --git a/homeassistant/components/axis/manifest.json b/homeassistant/components/axis/manifest.json
index 0f2b39b9760e9a..4d102590184b6c 100644
--- a/homeassistant/components/axis/manifest.json
+++ b/homeassistant/components/axis/manifest.json
@@ -2,11 +2,7 @@
   "domain": "axis",
   "name": "Axis",
   "documentation": "https://www.home-assistant.io/components/axis",
-  "requirements": [
-    "axis==20"
-  ],
+  "requirements": ["axis==21"],
   "dependencies": [],
-  "codeowners": [
-    "@kane610"
-  ]
+  "codeowners": ["@kane610"]
 }
diff --git a/requirements_all.txt b/requirements_all.txt
index 89054e68d62ebe..92627b444f7b48 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -192,7 +192,7 @@ av==6.1.2
 # avion==0.10
 
 # homeassistant.components.axis
-axis==20
+axis==21
 
 # homeassistant.components.baidu
 baidu-aip==1.6.6
diff --git a/requirements_test_all.txt b/requirements_test_all.txt
index 30903911e4f893..0b7da328ee1aba 100644
--- a/requirements_test_all.txt
+++ b/requirements_test_all.txt
@@ -61,7 +61,7 @@ apns2==0.3.0
 av==6.1.2
 
 # homeassistant.components.axis
-axis==20
+axis==21
 
 # homeassistant.components.zha
 bellows-homeassistant==0.7.2
diff --git a/tests/components/axis/test_config_flow.py b/tests/components/axis/test_config_flow.py
index 0ce5757578d0b6..1a83e9be8b54df 100644
--- a/tests/components/axis/test_config_flow.py
+++ b/tests/components/axis/test_config_flow.py
@@ -6,8 +6,6 @@
 
 from tests.common import mock_coro, MockConfigEntry
 
-import axis as axis_lib
-
 
 async def test_configured_devices(hass):
     """Test that configured devices works as expected."""
@@ -37,13 +35,9 @@ def mock_constructor(
             mock_device.port = port
             return mock_device
 
-        def mock_get_param(param):
-            """Fake get param method."""
-            return param
-
         mock_device.side_effect = mock_constructor
-        mock_device.vapix.load_params.return_value = Mock()
-        mock_device.vapix.get_param.side_effect = mock_get_param
+        mock_device.vapix.params.system_serialnumber = 'serialnumber'
+        mock_device.vapix.params.prodnbr = 'prodnbr'
 
         result = await hass.config_entries.flow.async_init(
             config_flow.DOMAIN,
@@ -59,23 +53,22 @@ def mock_get_param(param):
                 config_flow.CONF_HOST: '1.2.3.4',
                 config_flow.CONF_USERNAME: 'user',
                 config_flow.CONF_PASSWORD: 'pass',
-                config_flow.CONF_PORT: 81
+                config_flow.CONF_PORT: 80
             }
         )
 
     assert result['type'] == 'create_entry'
-    assert result['title'] == '{} - {}'.format(
-        axis_lib.vapix.VAPIX_MODEL_ID, axis_lib.vapix.VAPIX_SERIAL_NUMBER)
+    assert result['title'] == '{} - {}'.format('prodnbr', 'serialnumber')
     assert result['data'] == {
         axis.CONF_DEVICE: {
             config_flow.CONF_HOST: '1.2.3.4',
             config_flow.CONF_USERNAME: 'user',
             config_flow.CONF_PASSWORD: 'pass',
-            config_flow.CONF_PORT: 81
+            config_flow.CONF_PORT: 80
         },
-        config_flow.CONF_MAC: axis_lib.vapix.VAPIX_SERIAL_NUMBER,
-        config_flow.CONF_MODEL: axis_lib.vapix.VAPIX_MODEL_ID,
-        config_flow.CONF_NAME: 'Brand.ProdNbr 0'
+        config_flow.CONF_MAC: 'serialnumber',
+        config_flow.CONF_MODEL: 'prodnbr',
+        config_flow.CONF_NAME: 'prodnbr 0'
     }
 
 
@@ -89,7 +82,7 @@ async def test_flow_fails_already_configured(hass):
     entry.add_to_hass(hass)
 
     mock_device = Mock()
-    mock_device.vapix.get_param.return_value = '1234'
+    mock_device.vapix.params.system_serialnumber = '1234'
 
     with patch('homeassistant.components.axis.config_flow.get_device',
                return_value=mock_coro(mock_device)):
@@ -97,7 +90,7 @@ async def test_flow_fails_already_configured(hass):
             config_flow.CONF_HOST: '1.2.3.4',
             config_flow.CONF_USERNAME: 'user',
             config_flow.CONF_PASSWORD: 'pass',
-            config_flow.CONF_PORT: 81
+            config_flow.CONF_PORT: 80
         })
 
     assert result['errors'] == {'base': 'already_configured'}
@@ -114,7 +107,7 @@ async def test_flow_fails_faulty_credentials(hass):
             config_flow.CONF_HOST: '1.2.3.4',
             config_flow.CONF_USERNAME: 'user',
             config_flow.CONF_PASSWORD: 'pass',
-            config_flow.CONF_PORT: 81
+            config_flow.CONF_PORT: 80
         })
 
     assert result['errors'] == {'base': 'faulty_credentials'}
@@ -131,7 +124,7 @@ async def test_flow_fails_device_unavailable(hass):
             config_flow.CONF_HOST: '1.2.3.4',
             config_flow.CONF_USERNAME: 'user',
             config_flow.CONF_PASSWORD: 'pass',
-            config_flow.CONF_PORT: 81
+            config_flow.CONF_PORT: 80
         })
 
     assert result['errors'] == {'base': 'device_unavailable'}
@@ -207,13 +200,7 @@ def mock_constructor(
             mock_device.port = port
             return mock_device
 
-        def mock_get_param(param):
-            """Fake get param method."""
-            return param
-
         mock_device.side_effect = mock_constructor
-        mock_device.vapix.load_params.return_value = Mock()
-        mock_device.vapix.get_param.side_effect = mock_get_param
 
         result = await hass.config_entries.flow.async_init(
             config_flow.DOMAIN,
@@ -303,13 +290,9 @@ def mock_constructor(
             mock_device.port = port
             return mock_device
 
-        def mock_get_param(param):
-            """Fake get param method."""
-            return param
-
         mock_device.side_effect = mock_constructor
-        mock_device.vapix.load_params.return_value = Mock()
-        mock_device.vapix.get_param.side_effect = mock_get_param
+        mock_device.vapix.params.system_serialnumber = 'serialnumber'
+        mock_device.vapix.params.prodnbr = 'prodnbr'
 
         result = await hass.config_entries.flow.async_init(
             config_flow.DOMAIN,
@@ -324,8 +307,7 @@ def mock_get_param(param):
         )
 
     assert result['type'] == 'create_entry'
-    assert result['title'] == '{} - {}'.format(
-        axis_lib.vapix.VAPIX_MODEL_ID, axis_lib.vapix.VAPIX_SERIAL_NUMBER)
+    assert result['title'] == '{} - {}'.format('prodnbr', 'serialnumber')
     assert result['data'] == {
         axis.CONF_DEVICE: {
             config_flow.CONF_HOST: '1.2.3.4',
@@ -333,7 +315,7 @@ def mock_get_param(param):
             config_flow.CONF_PASSWORD: 'pass',
             config_flow.CONF_PORT: 80
         },
-        config_flow.CONF_MAC: axis_lib.vapix.VAPIX_SERIAL_NUMBER,
-        config_flow.CONF_MODEL: axis_lib.vapix.VAPIX_MODEL_ID,
+        config_flow.CONF_MAC: 'serialnumber',
+        config_flow.CONF_MODEL: 'prodnbr',
         config_flow.CONF_NAME: 'name'
     }
diff --git a/tests/components/axis/test_device.py b/tests/components/axis/test_device.py
index f6d17a3ef38ec6..d95352abe9c01b 100644
--- a/tests/components/axis/test_device.py
+++ b/tests/components/axis/test_device.py
@@ -190,8 +190,10 @@ async def test_shutdown():
 
 async def test_get_device(hass):
     """Successful call."""
-    with patch('axis.vapix.Vapix.load_params',
-               return_value=mock_coro()):
+    with patch('axis.param_cgi.Params.update_brand',
+               return_value=mock_coro()), \
+            patch('axis.param_cgi.Params.update_properties',
+                  return_value=mock_coro()):
         assert await device.get_device(hass, DEVICE_DATA)
 
 
@@ -199,7 +201,7 @@ async def test_get_device_fails(hass):
     """Device unauthorized yields authentication required error."""
     import axis
 
-    with patch('axis.vapix.Vapix.load_params',
+    with patch('axis.param_cgi.Params.update_brand',
                side_effect=axis.Unauthorized), \
             pytest.raises(errors.AuthenticationRequired):
         await device.get_device(hass, DEVICE_DATA)
@@ -209,7 +211,7 @@ async def test_get_device_device_unavailable(hass):
     """Device unavailable yields cannot connect error."""
     import axis
 
-    with patch('axis.vapix.Vapix.load_params',
+    with patch('axis.param_cgi.Params.update_brand',
                side_effect=axis.RequestError), \
             pytest.raises(errors.CannotConnect):
         await device.get_device(hass, DEVICE_DATA)
@@ -219,7 +221,7 @@ async def test_get_device_unknown_error(hass):
     """Device yield unknown error."""
     import axis
 
-    with patch('axis.vapix.Vapix.load_params',
+    with patch('axis.param_cgi.Params.update_brand',
                side_effect=axis.AxisException), \
             pytest.raises(errors.AuthenticationRequired):
         await device.get_device(hass, DEVICE_DATA)

<!--
## Breaking Change:
-->
<!-- What is breaking and why we have to break it. Remove this section only if it was NOT a breaking change. -->

## Description:
This will result in a faster startup per entry since less network data will be retrieved.
<!--
**Related issue (if applicable):** fixes #<home-assistant issue number goes here>

**Pull request in [home-assistant.io](https://github.com/home-assistant/home-assistant.io) with documentation (if applicable):** home-assistant/home-assistant.io#<home-assistant.io PR number goes here>
-->
## Checklist:
  - [x] The code change is tested and works locally.
  - [x] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass**
  - [x] There is no commented out code in this PR.

<!--
If user exposed functionality or configuration variables are added/changed:
  - [ ] Documentation added/updated in [home-assistant.io](https://github.com/home-assistant/home-assistant.io)

If the code communicates with devices, web services, or third-party tools:
  - [ ] [_The manifest file_][manifest-docs] has all fields filled out correctly ([example][ex-manifest]).
  - [ ] New dependencies have been added to `requirements` in the manifest ([example][ex-requir]).
  - [ ] New dependencies are only imported inside functions that use them ([example][ex-import]).
  - [ ] New or updated dependencies have been added to `requirements_all.txt` by running `script/gen_requirements_all.py`.
  - [ ] New files were added to `.coveragerc`.
-->
If the code does not interact with devices:
  - [x] Tests have been added to verify that the new code works.

[ex-manifest]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/mobile_app/manifest.json
[ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/mobile_app/manifest.json#L5
[ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23
[manifest-docs]: https://developers.home-assistant.io/docs/en/development_checklist.html#_the-manifest-file_