diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index fae621670ecba4e76aea7efb054235e57edd6b21..3d65df477e7605307410b44624bb9286c8a9379d 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -518,25 +518,24 @@ jobs:
   hassfest:
     name: Check hassfest
     runs-on: ubuntu-latest
-    needs: prepare-base
+    needs: prepare-tests
+    strategy:
+      matrix:
+        python-version: [3.7]
+    container: homeassistant/ci-azure:${{ matrix.python-version }}
     steps:
       - name: Check out code from GitHub
         uses: actions/checkout@v2
-      - name: Set up Python ${{ env.DEFAULT_PYTHON }}
-        uses: actions/setup-python@v2.1.2
-        id: python
-        with:
-          python-version: ${{ env.DEFAULT_PYTHON }}
-      - name: Restore base Python virtual environment
+      - name:
+          Restore full Python ${{ matrix.python-version }} virtual environment
         id: cache-venv
         uses: actions/cache@v2
         with:
           path: venv
           key: >-
-            ${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{
-            steps.python.outputs.python-version }}-${{
-            hashFiles('requirements.txt') }}-${{
-            hashFiles('requirements_test.txt') }}-${{
+            ${{ env.CACHE_VERSION}}-${{ runner.os }}-venv-${{
+            matrix.python-version }}-${{ hashFiles('requirements_test.txt')
+            }}-${{ hashFiles('requirements_all.txt') }}-${{
             hashFiles('homeassistant/package_constraints.txt') }}
       - name: Fail job if Python cache restore failed
         if: steps.cache-venv.outputs.cache-hit != 'true'
@@ -546,7 +545,7 @@ jobs:
       - name: Run hassfest
         run: |
           . venv/bin/activate
-          python -m script.hassfest --action validate
+          python -m script.hassfest --requirements --action validate
 
   gen-requirements-all:
     name: Check all requirements
diff --git a/homeassistant/components/homekit_controller/manifest.json b/homeassistant/components/homekit_controller/manifest.json
index 1ee2f16ffcfd34bf8d0eb60063d8bb6829d5a3b7..06199e9f2102a867ad069feb417c6ba45cfe7957 100644
--- a/homeassistant/components/homekit_controller/manifest.json
+++ b/homeassistant/components/homekit_controller/manifest.json
@@ -3,8 +3,16 @@
   "name": "HomeKit Controller",
   "config_flow": true,
   "documentation": "https://www.home-assistant.io/integrations/homekit_controller",
-  "requirements": ["aiohomekit[IP]==0.2.49"],
-  "zeroconf": ["_hap._tcp.local."],
-  "after_dependencies": ["zeroconf"],
-  "codeowners": ["@Jc2k"]
+  "requirements": [
+    "aiohomekit==0.2.49"
+  ],
+  "zeroconf": [
+    "_hap._tcp.local."
+  ],
+  "after_dependencies": [
+    "zeroconf"
+  ],
+  "codeowners": [
+    "@Jc2k"
+  ]
 }
diff --git a/homeassistant/components/samsungtv/manifest.json b/homeassistant/components/samsungtv/manifest.json
index efcb9064208b667ef651a27a02872e6d27a8aeef..5584d2dd452bdc5561f69d66c530376c7c6c3edc 100644
--- a/homeassistant/components/samsungtv/manifest.json
+++ b/homeassistant/components/samsungtv/manifest.json
@@ -4,13 +4,15 @@
   "documentation": "https://www.home-assistant.io/integrations/samsungtv",
   "requirements": [
     "samsungctl[websocket]==0.7.1",
-    "samsungtvws[websocket]==1.4.0"
+    "samsungtvws==1.4.0"
   ],
   "ssdp": [
     {
       "st": "urn:samsung.com:device:RemoteControlReceiver:1"
     }
   ],
-  "codeowners": ["@escoand"],
+  "codeowners": [
+    "@escoand"
+  ],
   "config_flow": true
 }
diff --git a/requirements_all.txt b/requirements_all.txt
index 82bb470b4cde29324a167b6b36fcc290b349025e..a2256a6ea825e92d66f75dec487dd4f337f46e04 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -2,7 +2,7 @@
 -r requirements.txt
 
 # homeassistant.components.nuimo_controller
---only-binary=all nuimo==0.1.0
+# --only-binary=all nuimo==0.1.0
 
 # homeassistant.components.dht
 # Adafruit-DHT==1.4.0
@@ -178,7 +178,7 @@ aioguardian==1.0.1
 aioharmony==0.2.6
 
 # homeassistant.components.homekit_controller
-aiohomekit[IP]==0.2.49
+aiohomekit==0.2.49
 
 # homeassistant.components.emulated_hue
 # homeassistant.components.http
@@ -1942,7 +1942,7 @@ saltbox==0.1.3
 samsungctl[websocket]==0.7.1
 
 # homeassistant.components.samsungtv
-samsungtvws[websocket]==1.4.0
+samsungtvws==1.4.0
 
 # homeassistant.components.satel_integra
 satel_integra==0.3.4
diff --git a/requirements_test_all.txt b/requirements_test_all.txt
index 3ca516c0b3ab374847bd28e9e531994b3d6fd941..f4acc7ae79c060ac45202f3d9f98ed7675954b72 100644
--- a/requirements_test_all.txt
+++ b/requirements_test_all.txt
@@ -103,7 +103,7 @@ aioguardian==1.0.1
 aioharmony==0.2.6
 
 # homeassistant.components.homekit_controller
-aiohomekit[IP]==0.2.49
+aiohomekit==0.2.49
 
 # homeassistant.components.emulated_hue
 # homeassistant.components.http
@@ -905,7 +905,7 @@ rxv==0.6.0
 samsungctl[websocket]==0.7.1
 
 # homeassistant.components.samsungtv
-samsungtvws[websocket]==1.4.0
+samsungtvws==1.4.0
 
 # homeassistant.components.emulated_kasa
 # homeassistant.components.sense
diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py
index 27482a0c215865030740f00a7a0245444c235065..62b1a22cc73cd8125e1638aa59e1a9133f5dabb2 100755
--- a/script/gen_requirements_all.py
+++ b/script/gen_requirements_all.py
@@ -23,11 +23,13 @@ COMMENT_REQUIREMENTS = (
     "bme680",
     "credstash",
     "decora",
+    "decora_wifi",
     "env_canada",
     "envirophat",
     "evdev",
     "face_recognition",
     "i2csense",
+    "nuimo",
     "opencv-python-headless",
     "py_noaa",
     "pybluez",
diff --git a/script/hassfest/requirements.py b/script/hassfest/requirements.py
index c2173cc1d131221a08c20f0b21132d8da9108551..b51cbff7185408b01eaf359543d6138c97b13236 100644
--- a/script/hassfest/requirements.py
+++ b/script/hassfest/requirements.py
@@ -2,6 +2,7 @@
 from collections import deque
 import json
 import operator
+import os
 import re
 import subprocess
 import sys
@@ -31,6 +32,19 @@ SUPPORTED_PYTHON_VERSIONS = [
 STD_LIBS = {version: set(stdlib_list(version)) for version in SUPPORTED_PYTHON_VERSIONS}
 PIPDEPTREE_CACHE = None
 
+IGNORE_VIOLATIONS = {
+    # Still has standard library requirements.
+    "acmeda",
+    "blink",
+    "ezviz",
+    "hdmi_cec",
+    "juicenet",
+    "lupusec",
+    "rainbird",
+    "slide",
+    "suez_water",
+}
+
 
 def normalize_package_name(requirement: str) -> str:
     """Return a normalized package name from a requirement string."""
@@ -49,12 +63,10 @@ def validate(integrations: Dict[str, Integration], config: Config):
     ensure_cache()
 
     # check for incompatible requirements
-    items = integrations.values()
 
-    if not config.specific_integrations:
-        tqdm(items)
+    disable_tqdm = config.specific_integrations or os.environ.get("CI", False)
 
-    for integration in items:
+    for integration in tqdm(integrations.values(), disable=disable_tqdm):
         if not integration.manifest:
             continue
 
@@ -63,6 +75,10 @@ def validate(integrations: Dict[str, Integration], config: Config):
 
 def validate_requirements(integration: Integration):
     """Validate requirements."""
+    # Some integrations have not been fixed yet so are allowed to have violations.
+    if integration.domain in IGNORE_VIOLATIONS:
+        return
+
     integration_requirements = set()
     integration_packages = set()
     for req in integration.requirements: