diff --git a/appdaemon/settings/apps/light/salt_lamp.py b/appdaemon/settings/apps/light/salt_lamp.py deleted file mode 100644 index e88938a..0000000 --- a/appdaemon/settings/apps/light/salt_lamp.py +++ /dev/null @@ -1,46 +0,0 @@ -import appdaemon.plugins.hass.hassapi as hass - -class Noolite(hass.Hass): - brightness = 40 - force = False - - def initialize(self): - self.run_at_sunrise(self.sunrise_cb) - # self.run_at_sunset(self.sunset_cb) - self.listen_state(self.light_change, "group.mainroom_light") - self.listen_event(self.away_mode, "away_mode") - - def away_mode(self, event_id, event_args, kwargs): - self.noolite_off() - - def light_change(self, entity, attribute, old, new, kwargs): - sun_down = self.sun_down() - if new == "off" and (sun_down or self.force) and self.somebody_home(): - self.noolite_on(self.brightness) - else: - self.noolite_off() - - def noolite_off(self): - self.log("Turning off salt lamp.") - self.turn_off(self.args['entity_id']) - - def noolite_on(self, brightness=120): - self.log("Turning on salt lamp for brightness {}.".format(brightness)) - self.turn_on(self.args['entity_id'], brightness=self.brightness) - - def sunset_cb(self, kwargs): - if not self.somebody_home(): - return - self.noolite_on(self.brightness) - - def somebody_home(self): - if 'ha_panel' not in self.args: - return True - ha_panel_state = self.get_state(self.args['ha_panel']) - if ha_panel_state == 'armed_away': - return False - return True - - - def sunrise_cb(self, kwargs): - self.noolite_off() diff --git a/appdaemon/settings/apps/light/salt_lamp.yaml b/appdaemon/settings/apps/light/salt_lamp.yaml deleted file mode 100644 index 973715c..0000000 --- a/appdaemon/settings/apps/light/salt_lamp.yaml +++ /dev/null @@ -1,5 +0,0 @@ -salt_lamp: - module: salt_lamp - class: Noolite - entity_id: light.salt_lamp - ha_panel: alarm_control_panel.ha_alarm diff --git a/esphome/settings/bath_light.yaml b/esphome/settings/bath_light.yaml deleted file mode 100644 index f1c552b..0000000 --- a/esphome/settings/bath_light.yaml +++ /dev/null @@ -1,51 +0,0 @@ -esphome: - name: bath_light - platform: ESP8266 - board: esp01_1m - -wifi: - ssid: !secret wifi_24_name - password: !secret wifi_24_pass - - # Enable fallback hotspot (captive portal) in case wifi connection fails - ap: - ssid: "BathLight Fallback Hotspot" - password: !secret esphome_captive_pass - -logger: - -api: - password: !secret esphome_pass - -ota: - password: !secret esphome_pass - -binary_sensor: - - platform: gpio - pin: - number: GPIO14 - mode: INPUT_PULLUP - inverted: True - id: button_1 - on_press: - then: - - light.toggle: light_1 - - - platform: status - name: "Bath status" - -output: - - platform: gpio - pin: GPIO12 - id: relay_1 - -light: - - platform: binary - name: "bath" - id: light_1 - output: relay_1 - -status_led: - pin: - number: GPIO13 - inverted: yes \ No newline at end of file diff --git a/esphome/settings/senseair.yaml b/esphome/settings/senseair.yaml deleted file mode 100644 index 6cde881..0000000 --- a/esphome/settings/senseair.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# Need to turn off logging because senseair uses uart and have conflicts with logging -logger: - baud_rate: 0 - -esphome: - name: senseair - platform: ESP8266 - board: d1_mini - -wifi: - ssid: !secret wifi_24_name - password: !secret wifi_24_pass - - # Enable fallback hotspot (captive portal) in case wifi connection fails - ap: - ssid: "Senseair Fallback Hotspot" - password: !secret esphome_captive_pass - -captive_portal: - -# Enable Home Assistant API -api: - password: !secret esphome_pass - -ota: - password: !secret esphome_pass - -# senseair communication uart -uart: - rx_pin: D7 - tx_pin: D8 - baud_rate: 9600 - -# hass sensor =) -sensor: - - platform: senseair - co2: - name: "SenseAir CO2 Value" - update_interval: 60s - diff --git a/esphome/settings/water_counters.h b/esphome/settings/water_counters.h new file mode 100644 index 0000000..d54c654 --- /dev/null +++ b/esphome/settings/water_counters.h @@ -0,0 +1,137 @@ +#include "esphome.h" +#include + +#define CounterNum 2 +#define COUNTER_COLD 0 +#define COUNTER_HOT 1 + +static const char *TAG = "watercounter.sensor"; + +class WaterCountersSensor : public Component, public Sensor, public CustomAPIDevice { + protected: + int CounterPin[CounterNum] = {D1,D2}; + float CounterValues[CounterNum] = {}; + Bounce CounterBouncer[CounterNum] = {}; + + public: + Sensor *cold_sensor = new Sensor(); + Sensor *hot_sensor = new Sensor(); + bool initReadValues = false; + + globals::GlobalsComponent *counter_cold_value; + globals::GlobalsComponent *counter_hot_value; + + void setup() override { + register_service(&WaterCountersSensor::on_set_counter_values, "set_counter_values", + {"cold_value", "hot_value"}); + + // init flash variables + counter_cold_value = new globals::GlobalsComponent(); + App.register_component(counter_cold_value); + counter_cold_value->set_restore_value(1547432152); + + counter_hot_value = new globals::GlobalsComponent(); + App.register_component(counter_hot_value); + counter_hot_value->set_restore_value(2087162808); + + ESP_LOGD(TAG, "Initializing counters."); + for (int i=0; ivalue(); + }else if (counterId == COUNTER_HOT) { + CounterValues[COUNTER_HOT] = counter_hot_value->value(); + } + } + + void writeFile(int counterId) { + if (counterId == COUNTER_COLD) { + counter_cold_value->value() = CounterValues[COUNTER_COLD]; + }else if (counterId == COUNTER_HOT) { + counter_hot_value->value() = CounterValues[COUNTER_HOT]; + } + ESP_LOGD(TAG, "Saving done."); + } + + void sendCounterValue(int counterId) { + if (counterId == COUNTER_COLD) { + ESP_LOGD(TAG, "Publishing cold state."); + float value = CounterValues[counterId]; + cold_sensor->publish_state(value); + }else if (counterId == COUNTER_HOT) { + ESP_LOGD(TAG, "Publishing hot state."); + float value = CounterValues[counterId]; + hot_sensor->publish_state(value); + } + } + + String countrName(int Id) { + switch(Id) { + case COUNTER_HOT: + return "hot"; + case COUNTER_COLD: + return "cold"; + } + return "unknown"; + } + + void printState(int counterId) { + ESP_LOGD(TAG, "Counter[%d]=%.2f", counterId, CounterValues[counterId]); + } +}; \ No newline at end of file diff --git a/esphome/settings/watercontrol.yaml b/esphome/settings/watercontrol.yaml index 0cb5c82..09685cd 100644 --- a/esphome/settings/watercontrol.yaml +++ b/esphome/settings/watercontrol.yaml @@ -2,10 +2,6 @@ substitutions: devicename: watercontrol upper_devicename: Watercontrol - pin_cold: D1 - init_cold: '216.08' - pin_hot: D2 - init_hot: '112.3' water_open_pin: D5 water_close_pin: D3 ultrasonic_echo_pin: D6 @@ -19,6 +15,10 @@ esphome: name: $devicename platform: ESP8266 board: d1_mini + libraries: + - "Bounce2" + includes: + - water_counters.h wifi: ssid: !secret wifi_24_name @@ -43,58 +43,25 @@ globals: type: bool restore_value: yes initial_value: 'true' - - id: counter_cold_value - type: float - restore_value: yes - initial_value: $init_cold - - id: counter_hot_value - type: float - restore_value: yes - initial_value: $init_hot - -binary_sensor: - - platform: gpio - id: pulse_cold - pin: - number: $pin_cold - mode: INPUT_PULLUP - filters: - - delayed_on: 1s - - delayed_off: 1s - on_press: - then: - - lambda: 'id(counter_cold_value) += 0.01;' - - - platform: gpio - id: pulse_hot - pin: - number: $pin_hot - mode: INPUT_PULLUP - filters: - - delayed_on: 1s - - delayed_off: 1s - on_press: - then: - - lambda: 'id(counter_hot_value) += 0.01;' +#------------------------------------------------------------------------------ sensor: - platform: uptime name: "$upper_devicename Uptime" - - platform: template - name: "counter_hot" - accuracy_decimals: 2 +#------------------------------------------------------------------------------ + - platform: custom lambda: |- - return id(counter_hot_value); - update_interval: 60s - - - platform: template - name: "counter_cold" - accuracy_decimals: 2 - lambda: |- - return id(counter_cold_value); - update_interval: 60s + auto my_sensor = new WaterCountersSensor(); + App.register_component(my_sensor); + return {my_sensor->cold_sensor, my_sensor->hot_sensor}; + sensors: + - name: "Counter Cold" + accuracy_decimals: 2 + - name: "Counter Hot" + accuracy_decimals: 2 +#------------------------------------------------------------------------------ - platform: ultrasonic trigger_pin: $ultrasonic_trig_pin echo_pin: $ultrasonic_echo_pin @@ -130,13 +97,4 @@ switch: - switch.turn_on: water_close - delay: 5s - switch.turn_off: water_close - - lambda: 'id(water_state) = false;' - - - platform: template - name: "Reset" - turn_on_action: - - lambda: 'id(counter_cold_value) = 216.08;' - - lambda: 'id(counter_hot_value) = 112.3;' - turn_off_action: - - lambda: 'id(counter_cold_value) = 216.08;' - - lambda: 'id(counter_hot_value) = 112.3;' + - lambda: 'id(water_state) = false;' \ No newline at end of file diff --git a/hass/settings/configuration.yaml b/hass/settings/configuration.yaml index fee615a..304e0f0 100644 --- a/hass/settings/configuration.yaml +++ b/hass/settings/configuration.yaml @@ -11,8 +11,6 @@ homeassistant: logger: default: info - logs: - custom_components.yandex_smart_home: debug api: @@ -68,7 +66,7 @@ remote: !include_dir_merge_list configuration/remote #one item mqtt: !include configuration/mqtt/mqtt.yaml telegram_bot: !include configuration/bot/telegram_bot.yaml -vacuum: !include configuration/xiaomi_aqara/vacuum.yaml +# vacuum: !include configuration/xiaomi_aqara/vacuum.yaml xiaomi_aqara: !include configuration/xiaomi_aqara/xiaomi_aqara.yaml nest: !include configuration/nest/nest.yaml homekit: !include configuration/homekit/homekit.yaml @@ -81,4 +79,4 @@ modbus: !include configuration/modbus.yaml utility_meter: !include_dir_merge_named configuration/utility_meter speedtestdotnet: !include configuration/speedtest.yaml -yandex_smart_home: !include configuration/alice.yaml +# yandex_smart_home: !include configuration/alice.yaml diff --git a/hass/settings/configuration/alice.yaml b/hass/settings/configuration/alice.yaml deleted file mode 100644 index 6073dd2..0000000 --- a/hass/settings/configuration/alice.yaml +++ /dev/null @@ -1,115 +0,0 @@ -filter: - include_domains: - - climate - - switch - - light - - vacuum - - cover - - fan - include_entities: - - input_boolean.alice_night_mode - - input_boolean.alice_turn_off_light - - input_boolean.alice_away_mode - - exclude_entities: - - switch.plug_158d00020f3a29 - - switch.plug_158d00026ea017 - - switch.plug_158d00010dd98d - - switch.xiaomi_miio_switch - - switch.domofon_mode - - switch.domofon_open - - light.gateway_light_f0b429aa1463 - - switch.domofon_automatically_open - - switch.domofon_automatically_open_once - - switch.domofon_force_open - - switch.wled_sync_receive - - switch.wled_sync_send - - switch.airfresher_fresh - - switch.airfresher_reset - - -entity_config: - input_boolean.alice_away_mode: - name: "Я ушёл" - room: "Сценарии" - input_boolean.alice_night_mode: - name: "Спокойной ночи" - room: "Сценарии" - input_boolean.alice_turn_off_light: - name: "Выключи свет" - room: "Сценарии" - climate.living_room: - name: "Термостат" - room: "Гостиная" - light.yeelight_mono1_f0b429a8f6df: - name: "Люстра" - room: "Гостиная" - light.yeelight_color1_34ce008fe328: - name: "Люстра" - room: "Гостиная" - light.yeelight_color1_286c071065c7: - name: "Люстра" - room: "Гостиная" - light.yeelight_mono1_f0b4290e5444: - name: "Люстра" - room: "Гостиная" - light.yeelight_mono1_34ce0087ff33: - name: "Люстра" - room: "Гостиная" - light.salt_lamp: - name: "Соляная лампа" - room: "Гостиная" - switch.wifi_socket: - name: "Гирлянда" - room: "Гостиная" - fan.xiaomi_miio_device: - name: "Воздухоочиститель" - room: "Гостиная" - switch.plug_158d0001104a0c: - name: "Телевизор" - room: "Гостиная" - cover.curtain_158d0002b0c46a: - name: "Шторы" - room: "Гостиная" - light.bath: - name: "Люстра" - room: "Туалет" - light.philips_led: - name: "Люстра" - room: "Туалет" - light.kitchen_mini_light: - name: "Подсветка" - room: "Кухня" - light.kitchen: - name: "Люстра" - room: "Кухня" - switch.plug_158d0001a68c64: - name: "Посудомойка" - room: "Кухня" - switch.plug_158d0001a4cfb4: - name: "Стиралка" - room: "Кухня" - light.hall: - name: "Люстра" - room: "Коридор" - switch.plug_158d0001a68b18: - name: "Термопот" - room: "Кухня" - light.yeelight_mono1_f0b429a8d936: - name: "Люстра" - room: "Балкон" - light.yeelight_mono1_286c07f12bed: - name: "Люстра" - room: "Балкон" - switch.plug_158d0002924779: - name: "Фитолампа" - room: "Балкон" - vacuum.xiaomi_vacuum_cleaner: - name: "Пылесос" - room: "Дом" - switch.water_valve: - name: "Подача воды" - room: "Дом" - light.wled: - name: "Ёлка" - room: "Гостиная" \ No newline at end of file diff --git a/hass/settings/configuration/appletv/appletv4.yaml b/hass/settings/configuration/appletv/appletv4.yaml deleted file mode 100644 index 51ea406..0000000 --- a/hass/settings/configuration/appletv/appletv4.yaml +++ /dev/null @@ -1,4 +0,0 @@ -- name: appletv4 - host: !secret atv4_ip - login_id: !secret atv4_login - credentials: !secret atv4_credentials \ No newline at end of file diff --git a/hass/settings/configuration/binary_sensor/door/balcony.yaml.bkp b/hass/settings/configuration/binary_sensor/door/balcony.yaml.bkp deleted file mode 100644 index cd08b3d..0000000 --- a/hass/settings/configuration/binary_sensor/door/balcony.yaml.bkp +++ /dev/null @@ -1,6 +0,0 @@ -- platform: mqtt - state_topic: "home/magnet/balcony/status" - name: "door_window_sensor_158d00010f7e19" - payload_on: "open" - payload_off: "close" - device_class: opening diff --git a/hass/settings/configuration/binary_sensor/door/bath.yaml.bkp b/hass/settings/configuration/binary_sensor/door/bath.yaml.bkp deleted file mode 100644 index a23e4f1..0000000 --- a/hass/settings/configuration/binary_sensor/door/bath.yaml.bkp +++ /dev/null @@ -1,6 +0,0 @@ -- platform: mqtt - state_topic: "home/magnet/bath/status" - name: "door_window_sensor_158d000111a469" - payload_on: "open" - payload_off: "close" - device_class: opening \ No newline at end of file diff --git a/hass/settings/configuration/binary_sensor/door/hall.yaml.bkp b/hass/settings/configuration/binary_sensor/door/hall.yaml.bkp deleted file mode 100644 index 0a3102f..0000000 --- a/hass/settings/configuration/binary_sensor/door/hall.yaml.bkp +++ /dev/null @@ -1,6 +0,0 @@ -- platform: mqtt - state_topic: "home/magnet/hall/status" - name: "door_window_sensor_158d0001130141" - payload_on: "open" - payload_off: "close" - device_class: opening diff --git a/hass/settings/configuration/binary_sensor/motion/bath.yaml.bkp b/hass/settings/configuration/binary_sensor/motion/bath.yaml.bkp deleted file mode 100644 index d09711e..0000000 --- a/hass/settings/configuration/binary_sensor/motion/bath.yaml.bkp +++ /dev/null @@ -1,18 +0,0 @@ -- platform: mqtt - state_topic: "home/motion/bath/status" - name: "motion_sensor_158d0000f9546b" #"bath_motion" - payload_on: "motion" - payload_off: "no_motion" - device_class: motion -- platform: mqtt - state_topic: "home/sensor_motion.aq2/bath2/status" - name: "motion_sensor_158d000165fed5" #"bath_motion2" - payload_on: "motion" - payload_off: "no_motion" - device_class: motion -- platform: mqtt - state_topic: "home/motion/bath3/status" - name: "motion_sensor_158d0001537e21" #"bath_motion3" - payload_on: "motion" - payload_off: "no_motion" - device_class: motion \ No newline at end of file diff --git a/hass/settings/configuration/binary_sensor/motion/hall.yaml.bkp b/hass/settings/configuration/binary_sensor/motion/hall.yaml.bkp deleted file mode 100644 index 8d552f9..0000000 --- a/hass/settings/configuration/binary_sensor/motion/hall.yaml.bkp +++ /dev/null @@ -1,6 +0,0 @@ -- platform: mqtt - state_topic: "home/motion/hall/status" - name: "motion_sensor_158d0000e7c7ad" - payload_on: "motion" - payload_off: "no_motion" - device_class: motion diff --git a/hass/settings/configuration/binary_sensor/motion/kitchen.yaml.bkp b/hass/settings/configuration/binary_sensor/motion/kitchen.yaml.bkp deleted file mode 100644 index 2a4f092..0000000 --- a/hass/settings/configuration/binary_sensor/motion/kitchen.yaml.bkp +++ /dev/null @@ -1,12 +0,0 @@ -- platform: mqtt - state_topic: "home/motion/kitchen/status" - name: "motion_sensor_158d0000fbc664" - payload_on: "motion" - payload_off: "no_motion" - device_class: motion -- platform: mqtt - state_topic: "home/motion/kitchen2/status" - name: "motion_sensor_158d0001535c97" - payload_on: "motion" - payload_off: "no_motion" - device_class: motion \ No newline at end of file diff --git a/hass/settings/configuration/binary_sensor/motion/mainroom.yaml.bkp b/hass/settings/configuration/binary_sensor/motion/mainroom.yaml.bkp deleted file mode 100644 index b12ab84..0000000 --- a/hass/settings/configuration/binary_sensor/motion/mainroom.yaml.bkp +++ /dev/null @@ -1,6 +0,0 @@ -- platform: mqtt - state_topic: "home/motion/mainroom/status" - name: "motion_sensor_158d0000f6b2fa" - payload_on: "motion" - payload_off: "no_motion" - device_class: motion diff --git a/hass/settings/configuration/binary_sensor/water/kitchen.yaml.bkp b/hass/settings/configuration/binary_sensor/water/kitchen.yaml.bkp deleted file mode 100644 index a22698d..0000000 --- a/hass/settings/configuration/binary_sensor/water/kitchen.yaml.bkp +++ /dev/null @@ -1,6 +0,0 @@ -- platform: mqtt - state_topic: "home/sensor_wleak.aq1/kitchen/status" - name: "water_leak_sensor_158d0001d594fa" - payload_on: "leak" - payload_off: "no_leak" - device_class: moisture diff --git a/hass/settings/configuration/fan/purifier.yaml.bkp b/hass/settings/configuration/fan/purifier.yaml.bkp deleted file mode 100644 index 1b49963..0000000 --- a/hass/settings/configuration/fan/purifier.yaml.bkp +++ /dev/null @@ -1,4 +0,0 @@ -- platform: xiaomi_miio - model: zhimi.airpurifier.mc1 - host: !secret purifier_ip - token: !secret purifier_key diff --git a/hass/settings/configuration/group/hidden/motion/bath_motion.yaml b/hass/settings/configuration/group/hidden/motion/bath_motion.yaml index d3cefb9..cdba230 100644 --- a/hass/settings/configuration/group/hidden/motion/bath_motion.yaml +++ b/hass/settings/configuration/group/hidden/motion/bath_motion.yaml @@ -2,6 +2,5 @@ bath_motion: name: Движение (ванна) control: hidden entities: - - binary_sensor.motion_sensor_158d0000f9546b - binary_sensor.motion_sensor_158d000165fed5 - binary_sensor.motion_sensor_158d0001537e21 \ No newline at end of file diff --git a/hass/settings/configuration/group/hidden/motion/hall_motion.yaml b/hass/settings/configuration/group/hidden/motion/hall_motion.yaml index d75b81a..ad66898 100644 --- a/hass/settings/configuration/group/hidden/motion/hall_motion.yaml +++ b/hass/settings/configuration/group/hidden/motion/hall_motion.yaml @@ -2,5 +2,4 @@ hall_motion: name: Движение (прихожая) control: hidden entities: - - binary_sensor.motion_sensor_158d0000e7c7ad - binary_sensor.motion_sensor_158d0002044548 \ No newline at end of file diff --git a/hass/settings/configuration/group/hidden/motion/kitchen_motion.yaml b/hass/settings/configuration/group/hidden/motion/kitchen_motion.yaml index b26a2ab..ad3e3d0 100644 --- a/hass/settings/configuration/group/hidden/motion/kitchen_motion.yaml +++ b/hass/settings/configuration/group/hidden/motion/kitchen_motion.yaml @@ -2,5 +2,4 @@ kitchen_motion: name: Движение (кухня) control: hidden entities: - - binary_sensor.motion_sensor_158d0000fbc664 - binary_sensor.motion_sensor_158d0001535c97 \ No newline at end of file diff --git a/hass/settings/configuration/group/hidden/motion/mainroom_motion.yaml b/hass/settings/configuration/group/hidden/motion/mainroom_motion.yaml index 2257453..a55ac7a 100644 --- a/hass/settings/configuration/group/hidden/motion/mainroom_motion.yaml +++ b/hass/settings/configuration/group/hidden/motion/mainroom_motion.yaml @@ -3,5 +3,4 @@ mainroom_motion: control: hidden entities: - binary_sensor.motion_sensor_158d0000f6b2fa - - binary_sensor.motion_sensor_158d0001e50ce4 - binary_sensor.motion_sensor_158d0001e80f0d \ No newline at end of file diff --git a/hass/settings/configuration/light/balcony.yaml b/hass/settings/configuration/light/balcony.yaml deleted file mode 100644 index a3c18dd..0000000 --- a/hass/settings/configuration/light/balcony.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# - platform: mqtt -# name: "balcony" -# state_topic: "stat/BALCONYV2/POWER" -# command_topic: "cmnd/BALCONYV2/POWER" -# payload_on: "ON" -# payload_off: "OFF" -# optimistic: false diff --git a/hass/settings/configuration/light/livingroom.yaml b/hass/settings/configuration/light/livingroom.yaml deleted file mode 100644 index d642306..0000000 --- a/hass/settings/configuration/light/livingroom.yaml +++ /dev/null @@ -1,13 +0,0 @@ - - platform: mqtt - name: "salt_lamp" - availability_topic: "home/noolite/$online" - payload_available: "true" - payload_not_available: "false" - state_topic: "home/noolite/ch0/power" - command_topic: "home/noolite/ch0/power/set" - on_command_type: first - payload_on: "on" - payload_off: "off" - brightness_state_topic: "home/noolite/ch0/brightness" - brightness_command_topic: "home/noolite/ch0/brightness/set" - brightness_scale: 120 diff --git a/hass/settings/configuration/mysensors.yaml b/hass/settings/configuration/mysensors.yaml deleted file mode 100644 index a653bbd..0000000 --- a/hass/settings/configuration/mysensors.yaml +++ /dev/null @@ -1,4 +0,0 @@ -#gateways: -# - device: !secret mysensors_gateway_ip -# tcp_port: 5003 -#version: '2.0' \ No newline at end of file diff --git a/hass/settings/configuration/remote/xiaomi.yaml b/hass/settings/configuration/remote/xiaomi.yaml deleted file mode 100644 index 6feca1d..0000000 --- a/hass/settings/configuration/remote/xiaomi.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# - platform: xiaomi_miio -# name: xiaomi_remote -# host: !secret xiaomi_remote_host -# token: !secret xiaomi_remote_token diff --git a/hass/settings/configuration/script/airfresher_reset.yaml b/hass/settings/configuration/script/airfresher_reset.yaml deleted file mode 100644 index 43e084b..0000000 --- a/hass/settings/configuration/script/airfresher_reset.yaml +++ /dev/null @@ -1,6 +0,0 @@ -airfresher_reset: - sequence: - - service: mqtt.publish - data: - topic: 'home/airfresher/airfresher/remain/set' - payload: 1500 \ No newline at end of file diff --git a/hass/settings/configuration/script/audio_bass_minus.yaml b/hass/settings/configuration/script/audio_bass_minus.yaml deleted file mode 100644 index 381f28c..0000000 --- a/hass/settings/configuration/script/audio_bass_minus.yaml +++ /dev/null @@ -1,6 +0,0 @@ -audio_bass_minus: - sequence: - - service: mqtt.publish - data: - topic: "home/remote/rm2/code/set" - payload: "260050000001339514371412131313131312131313131313131313381337133814371337143714371412133814361437141213131213131313381412131313131238143714371436140005060001334a14000d050000000000000000" diff --git a/hass/settings/configuration/script/audio_bass_plus.yaml b/hass/settings/configuration/script/audio_bass_plus.yaml deleted file mode 100644 index 70fc3c1..0000000 --- a/hass/settings/configuration/script/audio_bass_plus.yaml +++ /dev/null @@ -1,6 +0,0 @@ -audio_bass_plus: - sequence: - - service: mqtt.publish - data: - topic: "home/remote/rm2/code/set" - payload: "260050000001339414371412131313131213131313131313131313381436143714371437143713381412133813121338141213131313131313381312133814121338143614371437140005060001324a14000d050000000000000000" diff --git a/hass/settings/configuration/script/audio_vol_minus.yaml b/hass/settings/configuration/script/audio_vol_minus.yaml deleted file mode 100644 index f2b2784..0000000 --- a/hass/settings/configuration/script/audio_vol_minus.yaml +++ /dev/null @@ -1,6 +0,0 @@ -audio_vol_minus: - sequence: - - service: mqtt.publish - data: - topic: "home/remote/rm2/code/set" - payload: "260050000001329513381313131313121313131313131313131312381338133813371338133813381313121313131313133812131313131313381338123813381313123813381338120005060001314b13000d050000000000000000" diff --git a/hass/settings/configuration/script/audio_vol_plus.yaml b/hass/settings/configuration/script/audio_vol_plus.yaml deleted file mode 100644 index 9fb51e0..0000000 --- a/hass/settings/configuration/script/audio_vol_plus.yaml +++ /dev/null @@ -1,6 +0,0 @@ -audio_vol_plus: - sequence: - - service: mqtt.publish - data: - topic: "home/remote/rm2/code/set" - payload: "260058000001309613381213131313131213141214121313141113381437143614371437133714371437141213121313143713121313131313131238143713381313123814371436150005030001324916000c5b0001324914000d05" diff --git a/hass/settings/configuration/sensor/purifier.yaml b/hass/settings/configuration/sensor/purifier.yaml deleted file mode 100644 index 4488159..0000000 --- a/hass/settings/configuration/sensor/purifier.yaml +++ /dev/null @@ -1,7 +0,0 @@ - - platform: template - sensors: - xiaomi_airpurifier_air_quality_pm25: - friendly_name: "Air quality" - value_template: "{{ state_attr('fan.xiaomi_miio_device', 'aqi') }}" - unit_of_measurement: "μg/m³" - icon_template: "mdi:weather-fog" \ No newline at end of file diff --git a/hass/settings/configuration/switch/kitchen_mini_light.yaml b/hass/settings/configuration/switch/kitchen_mini_light.yaml deleted file mode 100644 index 5317e37..0000000 --- a/hass/settings/configuration/switch/kitchen_mini_light.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# - platform: mqtt -# name: kitchen_mini_light -# state_topic: "home/plug/kitchen-mini-light/status" -# command_topic: "home/plug/kitchen-mini-light/status/set" -# payload_on: "on" -# payload_off: "off" - -# - platform: broadlink -# host: 192.168.1.63 -# mac: 'B4430DCB6C07' -# type: 'sp2' -# friendly_name: 'kitchen_mini_light' \ No newline at end of file diff --git a/hass/settings/configuration/xiaomi_aqara/vacuum.yaml b/hass/settings/configuration/xiaomi_aqara/vacuum.yaml deleted file mode 100644 index 38e25b2..0000000 --- a/hass/settings/configuration/xiaomi_aqara/vacuum.yaml +++ /dev/null @@ -1,3 +0,0 @@ -- platform: xiaomi_miio - host: !secret mirobot_ip - token: !secret mirobot_key \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/__init__.py b/hass/settings/custom_components/hacs/__init__.py deleted file mode 100644 index 15f8034..0000000 --- a/hass/settings/custom_components/hacs/__init__.py +++ /dev/null @@ -1,187 +0,0 @@ -""" -Custom element manager for community created elements. - -For more details about this integration, please refer to the documentation at -https://hacs.xyz/ -""" -import voluptuous as vol -from aiogithubapi import AIOGitHub -from homeassistant import config_entries -from homeassistant.const import EVENT_HOMEASSISTANT_START -from homeassistant.const import __version__ as HAVERSION -from homeassistant.exceptions import ConfigEntryNotReady -from homeassistant.helpers.aiohttp_client import async_create_clientsession -from homeassistant.helpers.event import async_call_later - -from .configuration_schema import hacs_base_config_schema, hacs_config_option_schema -from .const import DEV_MODE, DOMAIN, ELEMENT_TYPES, STARTUP, VERSION -from .constrains import check_constans -from .hacsbase import Hacs -from .hacsbase.configuration import Configuration -from .hacsbase.data import HacsData -from .hacsbase.migration import ValidateData -from .setup import add_sensor, load_hacs_repository, setup_frontend - -SCHEMA = hacs_base_config_schema() -SCHEMA[vol.Optional("options")] = hacs_config_option_schema() -CONFIG_SCHEMA = vol.Schema({DOMAIN: SCHEMA}, extra=vol.ALLOW_EXTRA) - - -async def async_setup(hass, config): - """Set up this integration using yaml.""" - if DOMAIN not in config: - return True - hass.data[DOMAIN] = config - Hacs.hass = hass - Hacs.configuration = Configuration.from_dict( - config[DOMAIN], config[DOMAIN].get("options") - ) - Hacs.configuration.config_type = "yaml" - await startup_wrapper_for_yaml(Hacs) - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data={} - ) - ) - return True - - -async def async_setup_entry(hass, config_entry): - """Set up this integration using UI.""" - conf = hass.data.get(DOMAIN) - if config_entry.source == config_entries.SOURCE_IMPORT: - if conf is None: - hass.async_create_task( - hass.config_entries.async_remove(config_entry.entry_id) - ) - return False - Hacs.hass = hass - Hacs.configuration = Configuration.from_dict( - config_entry.data, config_entry.options - ) - Hacs.configuration.config_type = "flow" - Hacs.configuration.config_entry = config_entry - config_entry.add_update_listener(reload_hacs) - startup_result = await hacs_startup(Hacs) - if not startup_result: - raise ConfigEntryNotReady - return startup_result - - -async def startup_wrapper_for_yaml(hacs): - """Startup wrapper for yaml config.""" - startup_result = await hacs_startup(hacs) - if not startup_result: - hacs.hass.components.frontend.async_remove_panel( - hacs.configuration.sidepanel_title.lower() - .replace(" ", "_") - .replace("-", "_") - ) - hacs.logger.info("Could not setup HACS, trying again in 15 min") - async_call_later(hacs.hass, 900, startup_wrapper_for_yaml(hacs)) - - -async def hacs_startup(hacs): - """HACS startup tasks.""" - hacs.logger.debug(f"Configuration type: {hacs.configuration.config_type}") - hacs.version = VERSION - hacs.logger.info(STARTUP) - hacs.system.config_path = hacs.hass.config.path() - hacs.system.ha_version = HAVERSION - hacs.system.disabled = False - hacs.github = AIOGitHub( - hacs.configuration.token, async_create_clientsession(hacs.hass) - ) - hacs.data = HacsData() - - # Check HACS Constrains - if not check_constans(hacs): - if hacs.configuration.config_type == "flow": - if hacs.configuration.config_entry is not None: - await async_remove_entry(hacs.hass, hacs.configuration.config_entry) - return False - - # Set up frontend - await setup_frontend(hacs) - - # Load HACS - if not await load_hacs_repository(hacs): - if hacs.configuration.config_type == "flow": - if hacs.configuration.config_entry is not None: - await async_remove_entry(hacs.hass, hacs.configuration.config_entry) - return False - - val = ValidateData() - if not val.validate_local_data_file(): - if hacs.configuration.config_type == "flow": - if hacs.configuration.config_entry is not None: - await async_remove_entry(hacs.hass, hacs.configuration.config_entry) - return False - - # Restore from storefiles - if not await hacs.data.restore(): - hacs_repo = hacs().get_by_name("hacs/integration") - hacs_repo.pending_restart = True - if hacs.configuration.config_type == "flow": - if hacs.configuration.config_entry is not None: - await async_remove_entry(hacs.hass, hacs.configuration.config_entry) - return False - - # Add aditional categories - if hacs.configuration.appdaemon: - ELEMENT_TYPES.append("appdaemon") - if hacs.configuration.python_script: - ELEMENT_TYPES.append("python_script") - if hacs.configuration.theme: - ELEMENT_TYPES.append("theme") - hacs.common.categories = sorted(ELEMENT_TYPES) - - # Setup startup tasks - if hacs.configuration.config_type == "yaml": - hacs.hass.bus.async_listen_once( - EVENT_HOMEASSISTANT_START, hacs().startup_tasks() - ) - else: - async_call_later(hacs.hass, 5, hacs().startup_tasks()) - - # Print DEV warning - if hacs.configuration.dev: - hacs.logger.warning(DEV_MODE) - hacs.hass.components.persistent_notification.create( - title="HACS DEV MODE", message=DEV_MODE, notification_id="hacs_dev_mode" - ) - - # Add sensor - add_sensor(hacs) - - # Set up services - # await add_services(hacs) - - # Mischief managed! - return True - - -async def async_remove_entry(hass, config_entry): - """Handle removal of an entry.""" - Hacs().logger.info("Disabling HACS") - Hacs().logger.info("Removing recuring tasks") - for task in Hacs().tasks: - task() - Hacs().logger.info("Removing sensor") - try: - await hass.config_entries.async_forward_entry_unload(config_entry, "sensor") - except ValueError: - pass - Hacs().logger.info("Removing sidepanel") - try: - hass.components.frontend.async_remove_panel("hacs_web") - except AttributeError: - pass - Hacs().system.disabled = True - Hacs().logger.info("HACS is now disabled") - - -async def reload_hacs(hass, config_entry): - """Reload HACS.""" - await async_remove_entry(hass, config_entry) - await async_setup_entry(hass, config_entry) diff --git a/hass/settings/custom_components/hacs/api.py b/hass/settings/custom_components/hacs/api.py deleted file mode 100644 index fc064ec..0000000 --- a/hass/settings/custom_components/hacs/api.py +++ /dev/null @@ -1,421 +0,0 @@ -"""API Endpoins.""" -from time import time -from aiohttp import web - -from integrationhelper import Logger - -from .http import HacsWebResponse - -APIRESPONSE = {} - - -def apiresponse(classname): - """Decorator used to register API Responses.""" - APIRESPONSE[classname.name] = classname - return classname - - -class HacsAPI(HacsWebResponse): - """HacsAPI class.""" - - name = "hacsapi" - - def __init__(self): - """Initialize.""" - self.logger = Logger("hacs.api") - self.url = self.hacsapi + "/{endpoint}" - - async def post(self, request, endpoint): # pylint: disable=unused-argument - """Handle HACS API requests.""" - if self.system.disabled: - return web.Response(status=404) - self.endpoint = endpoint - self.postdata = await request.post() - self.raw_headers = request.raw_headers - self.request = request - self.logger.debug(f"Endpoint ({endpoint}) called") - if self.configuration.dev: - self.logger.debug(f"Raw headers ({self.raw_headers})") - self.logger.debug(f"Postdata ({self.postdata})") - if self.endpoint in APIRESPONSE: - try: - response = APIRESPONSE[self.endpoint] - response = await response.response(self) - except Exception as exception: - render = self.render(f"error", message=exception) - return web.Response( - body=render, content_type="text/html", charset="utf-8" - ) - else: - # Return default response. - response = await APIRESPONSE["generic"].response(self) - - # set headers - response.headers["Cache-Control"] = "max-age=0, must-revalidate" - - # serve the response - return response - - -class HacsRunningTask(HacsAPI): - """Return if BG task is running.""" - - name = "hacs:task" - - def __init__(self): - """Initialize.""" - self.url = "/hacs_task" - - async def get(self, request): # pylint: disable=unused-argument - """Handle GET request.""" - return web.json_response({"task": self.system.status.background_task}) - - -@apiresponse -class Generic(HacsAPI): - """Generic API response.""" - - name = "generic" - - async def response(self): - """Response.""" - self.logger.error(f"Unknown endpoint '{self.endpoint}'") - return web.HTTPFound(f"/hacsweb/{self.token}/settings?timestamp={time()}") - - -@apiresponse -class RemoveNewFlag(HacsAPI): - """Remove new flag on all repositories.""" - - name = "remove_new_flag" - - async def response(self): - """Response.""" - for repository in self.repositories: - repository.status.new = False - await self.data.async_write() - return web.HTTPFound( - f"/hacsweb/{self.token}/{self.postdata['return']}?timestamp={time()}" - ) - - -@apiresponse -class DevTemplate(HacsAPI): - """Remove new flag on all repositories.""" - - name = "dev_template" - - async def response(self): - """Response.""" - from .handler.template import render_template - - if "set" in self.postdata: - self.developer.template_id = self.postdata.get("repository_id") - repository = self.get_by_id(self.developer.template_id) - template = render_template(self.postdata.get("template", ""), repository) - info = await self.github.render_markdown(template) - info = info.replace("

", "

").replace("
", "") - info = info.replace("

", "

").replace("
", "") - info = info.replace("

", "

").replace("

", "") - info = info.replace("", "") - info = info.replace( - '", "") - info = info.replace("", "") - self.developer.template_content = info - else: - self.developer.template_content = "" - self.developer.template_id = "Repository ID" - render = self.render("settings/dev/template_test") - return web.Response(body=render, content_type="text/html", charset="utf-8") - - -@apiresponse -class DevView(HacsAPI): - """Set HA version view.""" - - name = "devview" - - async def response(self): - """Response.""" - render = self.render(f"settings/dev/{self.postdata['view']}") - return web.Response(body=render, content_type="text/html", charset="utf-8") - - -@apiresponse -class SetHAVersionAction(HacsAPI): - """Set HA version action.""" - - name = "set_ha_version_action" - - async def response(self): - """Response.""" - self.common.ha_version = self.postdata["ha_version"] - render = self.render("settings/dev/set_ha_version") - return web.Response(body=render, content_type="text/html", charset="utf-8") - - -@apiresponse -class RepositoryInstall(HacsAPI): - """Install repository.""" - - name = "repository_install" - - async def response(self): - """Response.""" - repository = self.get_by_id(self.postdata["repository_id"]) - await repository.install() - await self.data.async_write() - return web.HTTPFound( - f"/hacsweb/{self.token}/repository/{repository.information.uid}?timestamp={time()}" - ) - - -@apiresponse -class RepositoryUpdate(HacsAPI): - """Update repository.""" - - name = "repository_update" - - async def response(self): - """Response.""" - repository = self.get_by_id(self.postdata["repository_id"]) - await repository.update_repository() - await self.data.async_write() - return web.HTTPFound( - f"/hacsweb/{self.token}/repository/{repository.information.uid}?timestamp={time()}" - ) - - -@apiresponse -class RepositoryUninstall(HacsAPI): - """Uninstall repository.""" - - name = "repository_uninstall" - - async def response(self): - """Response.""" - repository = self.get_by_id(self.postdata["repository_id"]) - await repository.uninstall() - await self.data.async_write() - return web.HTTPFound(f"/hacsweb/{self.token}/overview?timestamp={time()}") - - -@apiresponse -class RepositoryRemove(HacsAPI): - """Remove repository.""" - - name = "repository_remove" - - async def response(self): - """Response.""" - repository = self.get_by_id(self.postdata["repository_id"]) - await repository.remove() - await self.data.async_write() - return web.HTTPFound(f"/hacsweb/{self.token}/settings?timestamp={time()}") - - -@apiresponse -class RepositoryHide(HacsAPI): - """Hide repository.""" - - name = "repository_hide" - - async def response(self): - """Response.""" - repository = self.get_by_id(self.postdata["repository_id"]) - repository.hide = True - await self.data.async_write() - return web.HTTPFound(f"/hacsweb/{self.token}/store?timestamp={time()}") - - -@apiresponse -class RepositoryUnhide(HacsAPI): - """Unhide repository.""" - - name = "repository_unhide" - - async def response(self): - """Response.""" - repository = self.get_by_id(self.postdata["repository_id"]) - repository.hide = False - await self.data.async_write() - return web.HTTPFound(f"/hacsweb/{self.token}/settings?timestamp={time()}") - - -@apiresponse -class RepositoryBetaHide(HacsAPI): - """Hide Beta repository.""" - - name = "repository_beta_hide" - - async def response(self): - """Response.""" - repository = self.get_by_id(self.postdata["repository_id"]) - repository.status.show_beta = False - await repository.update_repository() - await self.data.async_write() - return web.HTTPFound( - f"/hacsweb/{self.token}/repository/{repository.information.uid}?timestamp={time()}" - ) - - -@apiresponse -class RepositoryBetaShow(HacsAPI): - """Show Beta repository.""" - - name = "repository_beta_show" - - async def response(self): - """Response.""" - repository = self.get_by_id(self.postdata["repository_id"]) - repository.status.show_beta = True - await repository.update_repository() - await self.data.async_write() - return web.HTTPFound( - f"/hacsweb/{self.token}/repository/{repository.information.uid}?timestamp={time()}" - ) - - -@apiresponse -class RepositoriesReload(HacsAPI): - """Reload repository data.""" - - name = "repositories_reload" - - async def response(self): - """Response.""" - self.hass.async_create_task(self.recuring_tasks_all()) - return web.HTTPFound(f"/hacsweb/{self.token}/settings?timestamp={time()}") - - -@apiresponse -class RepositoriesUpgradeAll(HacsAPI): - """Upgrade all repositories.""" - - name = "repositories_upgrade_all" - - async def response(self): - """Response.""" - for repository in self.repositories: - if repository.pending_upgrade: - await repository.install() - await self.data.async_write() - return web.HTTPFound(f"/hacsweb/{self.token}/settings?timestamp={time()}") - - -@apiresponse -class RepositoryRegister(HacsAPI): - """Register repository.""" - - name = "repository_register" - - async def response(self): - """Response.""" - repository_name = self.postdata.get("custom_url") - repository_type = self.postdata.get("repository_type") - - # Validate data - if not repository_name: - message = "Repository URL is missing." - return web.HTTPFound( - f"/hacsweb/{self.token}/settings?timestamp={time()}&message={message}" - ) - if repository_type is None: - message = "Type is missing for '{}'.".format(repository_name) - return web.HTTPFound( - f"/hacsweb/{self.token}/settings?timestamp={time()}&message={message}" - ) - - # Stip first part if it's an URL. - if "github" in repository_name: - repository_name = repository_name.split("github.com/")[-1] - - # Strip whitespace - repository_name = repository_name.split()[0] - - # If it still have content, continue. - if repository_name != "": - if len(repository_name.split("/")) != 2: - message = f""" - {repository_name} is not a valid format. - Correct format is 'https://github.com/DEVELOPER/REPOSITORY' - or 'DEVELOPER/REPOSITORY'. - """ - - return web.HTTPFound( - f"/hacsweb/{self.token}/settings?timestamp={time()}&message={message}" - ) - - is_known_repository = self.is_known(repository_name) - if is_known_repository: - message = f"'{repository_name}' is already registered, look for it in the store." - return web.HTTPFound( - f"/hacsweb/{self.token}/settings?timestamp={time()}&message={message}" - ) - - if repository_name in self.common.blacklist: - self.common.blacklist.remove(repository_name) - - await self.register_repository(repository_name, repository_type) - - repository = self.get_by_name(repository_name) - if repository is not None: - return web.HTTPFound( - f"/hacsweb/{self.token}/repository/{repository.information.uid}?timestamp={time()}" - ) - - message = f""" - Could not add '{repository_name}' with type '{repository_type}' at this time.
- If you used the correct type, check the log for more details.""" - return web.HTTPFound( - f"/hacsweb/{self.token}/settings?timestamp={time()}&message={message}" - ) - - -@apiresponse -class RepositorySelectTag(HacsAPI): - """Select tag for Repository.""" - - name = "repository_select_tag" - - async def response(self): - """Response.""" - from aiogithubapi import AIOGitHubException - from .hacsbase.exceptions import HacsRequirement - - repository = self.get_by_id(self.postdata["repository_id"]) - if self.postdata["selected_tag"] == repository.releases.last_release: - repository.status.selected_tag = None - else: - repository.status.selected_tag = self.postdata["selected_tag"] - - try: - await repository.update_repository() - except (AIOGitHubException, HacsRequirement): - repository.status.selected_tag = repository.releases.last_release - await repository.update_repository() - message = "The version {} is not valid for use with HACS.".format( - self.postdata["selected_tag"] - ) - return web.HTTPFound( - f"/hacsweb/{self.token}/repository/{repository.information.uid}?timestamp={time()}&message={message}" - ) - await self.data.async_write() - return web.HTTPFound( - f"/hacsweb/{self.token}/repository/{repository.information.uid}?timestamp={time()}" - ) - - -@apiresponse -class FrontentMode(HacsAPI): - """Set the frontend mode.""" - - name = "frontend_mode" - - async def response(self): - """Response.""" - self.configuration.frontend_mode = self.postdata["view_type"] - await self.data.async_write() - return web.HTTPFound(f"/hacsweb/{self.token}/settings?timestamp={time()}") diff --git a/hass/settings/custom_components/hacs/config_flow.py b/hass/settings/custom_components/hacs/config_flow.py deleted file mode 100644 index cc392c7..0000000 --- a/hass/settings/custom_components/hacs/config_flow.py +++ /dev/null @@ -1,100 +0,0 @@ -"""Adds config flow for HACS.""" -# pylint: disable=dangerous-default-value -import logging -import voluptuous as vol -from aiogithubapi import AIOGitHub, AIOGitHubException, AIOGitHubAuthentication -from homeassistant import config_entries -from homeassistant.core import callback -from homeassistant.helpers import aiohttp_client - -from .const import DOMAIN -from .configuration_schema import hacs_base_config_schema, hacs_config_option_schema - - -_LOGGER = logging.getLogger(__name__) - - -class HacsFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): - """Config flow for HACS.""" - - VERSION = 1 - CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL - - def __init__(self): - """Initialize.""" - self._errors = {} - - async def async_step_user(self, user_input={}): - """Handle a flow initialized by the user.""" - self._errors = {} - if self._async_current_entries(): - return self.async_abort(reason="single_instance_allowed") - if self.hass.data.get(DOMAIN): - return self.async_abort(reason="single_instance_allowed") - - if user_input is not None: - if await self._test_token(user_input["token"]): - return self.async_create_entry(title="", data=user_input) - - self._errors["base"] = "auth" - return await self._show_config_form(user_input) - - return await self._show_config_form(user_input) - - async def _show_config_form(self, user_input): - """Show the configuration form to edit location data.""" - return self.async_show_form( - step_id="user", - data_schema=vol.Schema(hacs_base_config_schema(user_input)), - errors=self._errors, - ) - - @staticmethod - @callback - def async_get_options_flow(config_entry): - return HacsOptionsFlowHandler(config_entry) - - async def async_step_import(self, user_input): - """Import a config entry. - Special type of import, we're not actually going to store any data. - Instead, we're going to rely on the values that are in config file. - """ - if self._async_current_entries(): - return self.async_abort(reason="single_instance_allowed") - - return self.async_create_entry(title="configuration.yaml", data={}) - - async def _test_token(self, token): - """Return true if token is valid.""" - try: - session = aiohttp_client.async_get_clientsession(self.hass) - client = AIOGitHub(token, session) - await client.get_repo("hacs/org") - return True - except (AIOGitHubException, AIOGitHubAuthentication): - pass - return False - - -class HacsOptionsFlowHandler(config_entries.OptionsFlow): - """HACS config flow options handler.""" - - def __init__(self, config_entry): - """Initialize HACS options flow.""" - self.config_entry = config_entry - - async def async_step_init(self, user_input=None): - """Manage the options.""" - return await self.async_step_user() - - async def async_step_user(self, user_input=None): - """Handle a flow initialized by the user.""" - if user_input is not None: - return self.async_create_entry(title="", data=user_input) - - return self.async_show_form( - step_id="user", - data_schema=vol.Schema( - hacs_config_option_schema(self.config_entry.options) - ), - ) diff --git a/hass/settings/custom_components/hacs/configuration_schema.py b/hass/settings/custom_components/hacs/configuration_schema.py deleted file mode 100644 index ff88cfc..0000000 --- a/hass/settings/custom_components/hacs/configuration_schema.py +++ /dev/null @@ -1,49 +0,0 @@ -"""HACS Configuration Schemas.""" -# pylint: disable=dangerous-default-value -import voluptuous as vol -from .const import LOCALE - -# Configuration: -TOKEN = "token" -SIDEPANEL_TITLE = "sidepanel_title" -SIDEPANEL_ICON = "sidepanel_icon" -APPDAEMON = "appdaemon" -PYTHON_SCRIPT = "python_script" -THEME = "theme" - -# Options: -COUNTRY = "country" -RELEASE_LIMIT = "release_limit" -EXPERIMENTAL = "experimental" - - -def hacs_base_config_schema(config: dict = {}) -> dict: - """Return a shcema configuration dict for HACS.""" - if not config: - config = { - TOKEN: "xxxxxxxxxxxxxxxxxxxxxxxxxxx", - SIDEPANEL_TITLE: "Community", - SIDEPANEL_ICON: "mdi:alpha-c-box", - APPDAEMON: False, - PYTHON_SCRIPT: False, - THEME: False, - } - return { - vol.Required(TOKEN, default=config.get(TOKEN)): str, - vol.Optional(SIDEPANEL_TITLE, default=config.get(SIDEPANEL_TITLE)): str, - vol.Optional(SIDEPANEL_ICON, default=config.get(SIDEPANEL_ICON)): str, - vol.Optional(APPDAEMON, default=config.get(APPDAEMON)): bool, - vol.Optional(PYTHON_SCRIPT, default=config.get(PYTHON_SCRIPT)): bool, - vol.Optional(THEME, default=config.get(THEME)): bool, - } - - -def hacs_config_option_schema(options: dict = {}) -> dict: - """Return a shcema for HACS configuration options.""" - if not options: - options = {COUNTRY: "ALL", RELEASE_LIMIT: 5, EXPERIMENTAL: False} - return { - vol.Optional("country", default=options.get(COUNTRY)): vol.In(LOCALE), - vol.Optional(RELEASE_LIMIT, default=options.get(RELEASE_LIMIT)): int, - vol.Optional(EXPERIMENTAL, default=options.get(EXPERIMENTAL)): bool, - } diff --git a/hass/settings/custom_components/hacs/const.py b/hass/settings/custom_components/hacs/const.py deleted file mode 100644 index 529dbb0..0000000 --- a/hass/settings/custom_components/hacs/const.py +++ /dev/null @@ -1,295 +0,0 @@ -"""Constants for HACS""" -NAME_LONG = "HACS (Home Assistant Community Store)" -NAME_SHORT = "HACS" -VERSION = "0.16.3" -DOMAIN = "hacs" -PROJECT_URL = "https://github.com/hacs/integration/" -CUSTOM_UPDATER_LOCATIONS = [ - "{}/custom_components/custom_updater.py", - "{}/custom_components/custom_updater/__init__.py", -] - -ISSUE_URL = f"{PROJECT_URL}issues" -DOMAIN_DATA = f"{NAME_SHORT.lower()}_data" - -ELEMENT_TYPES = ["integration", "plugin"] - -IFRAME = { - "title": "Community", - "icon": "mdi:alpha-c-box", - "url": "/community_overview", - "path": "community", - "require_admin": True, -} - - -# Messages -CUSTOM_UPDATER_WARNING = """ -This cannot be used with custom_updater. -To use this you need to remove custom_updater form {} -""" - -DEV_MODE = "You have 'dev' enabled for HACS, this is not intended for regular use, no support will be given if you break something." - -STARTUP = f""" -------------------------------------------------------------------- -HACS (Home Assistant Community Store) - -Version: {VERSION} -This is a custom integration -If you have any issues with this you need to open an issue here: -https://github.com/hacs/integration/issues -------------------------------------------------------------------- -""" - -LOCALE = [ - "ALL", - "AF", - "AL", - "DZ", - "AS", - "AD", - "AO", - "AI", - "AQ", - "AG", - "AR", - "AM", - "AW", - "AU", - "AT", - "AZ", - "BS", - "BH", - "BD", - "BB", - "BY", - "BE", - "BZ", - "BJ", - "BM", - "BT", - "BO", - "BQ", - "BA", - "BW", - "BV", - "BR", - "IO", - "BN", - "BG", - "BF", - "BI", - "KH", - "CM", - "CA", - "CV", - "KY", - "CF", - "TD", - "CL", - "CN", - "CX", - "CC", - "CO", - "KM", - "CG", - "CD", - "CK", - "CR", - "HR", - "CU", - "CW", - "CY", - "CZ", - "CI", - "DK", - "DJ", - "DM", - "DO", - "EC", - "EG", - "SV", - "GQ", - "ER", - "EE", - "ET", - "FK", - "FO", - "FJ", - "FI", - "FR", - "GF", - "PF", - "TF", - "GA", - "GM", - "GE", - "DE", - "GH", - "GI", - "GR", - "GL", - "GD", - "GP", - "GU", - "GT", - "GG", - "GN", - "GW", - "GY", - "HT", - "HM", - "VA", - "HN", - "HK", - "HU", - "IS", - "IN", - "ID", - "IR", - "IQ", - "IE", - "IM", - "IL", - "IT", - "JM", - "JP", - "JE", - "JO", - "KZ", - "KE", - "KI", - "KP", - "KR", - "KW", - "KG", - "LA", - "LV", - "LB", - "LS", - "LR", - "LY", - "LI", - "LT", - "LU", - "MO", - "MK", - "MG", - "MW", - "MY", - "MV", - "ML", - "MT", - "MH", - "MQ", - "MR", - "MU", - "YT", - "MX", - "FM", - "MD", - "MC", - "MN", - "ME", - "MS", - "MA", - "MZ", - "MM", - "NA", - "NR", - "NP", - "NL", - "NC", - "NZ", - "NI", - "NE", - "NG", - "NU", - "NF", - "MP", - "NO", - "OM", - "PK", - "PW", - "PS", - "PA", - "PG", - "PY", - "PE", - "PH", - "PN", - "PL", - "PT", - "PR", - "QA", - "RO", - "RU", - "RW", - "RE", - "BL", - "SH", - "KN", - "LC", - "MF", - "PM", - "VC", - "WS", - "SM", - "ST", - "SA", - "SN", - "RS", - "SC", - "SL", - "SG", - "SX", - "SK", - "SI", - "SB", - "SO", - "ZA", - "GS", - "SS", - "ES", - "LK", - "SD", - "SR", - "SJ", - "SZ", - "SE", - "CH", - "SY", - "TW", - "TJ", - "TZ", - "TH", - "TL", - "TG", - "TK", - "TO", - "TT", - "TN", - "TR", - "TM", - "TC", - "TV", - "UG", - "UA", - "AE", - "GB", - "US", - "UM", - "UY", - "UZ", - "VU", - "VE", - "VN", - "VG", - "VI", - "WF", - "EH", - "YE", - "ZM", - "ZW", -] diff --git a/hass/settings/custom_components/hacs/constrains.py b/hass/settings/custom_components/hacs/constrains.py deleted file mode 100644 index cc8d52e..0000000 --- a/hass/settings/custom_components/hacs/constrains.py +++ /dev/null @@ -1,44 +0,0 @@ -"""HACS Startup constrains.""" -# pylint: disable=bad-continuation -import os -import json - -from .const import CUSTOM_UPDATER_LOCATIONS, CUSTOM_UPDATER_WARNING -from .helpers.misc import version_is_newer_than_version - - -def check_constans(hacs): - """Check HACS constrains.""" - if not constrain_custom_updater(hacs): - return False - if not constrain_version(hacs): - return False - return True - - -def constrain_custom_updater(hacs): - """Check if custom_updater exist.""" - for location in CUSTOM_UPDATER_LOCATIONS: - if os.path.exists(location.format(hacs.system.config_path)): - msg = CUSTOM_UPDATER_WARNING.format( - location.format(hacs.system.config_path) - ) - hacs.logger.critical(msg) - return False - return True - - -def constrain_version(hacs): - """Check if the version is valid.""" - with open( - f"{hacs.system.config_path}/custom_components/hacs/manifest.json", "r" - ) as read: - manifest = json.loads(read.read()) - - # Check if HA is the required version. - if version_is_newer_than_version(manifest["homeassistant"], hacs.system.ha_version): - hacs.logger.critical( - f"You need HA version {manifest['homeassistant']} or newer to use this integration." - ) - return False - return True diff --git a/hass/settings/custom_components/hacs/deprecated.py b/hass/settings/custom_components/hacs/deprecated.py deleted file mode 100644 index 43fd957..0000000 --- a/hass/settings/custom_components/hacs/deprecated.py +++ /dev/null @@ -1,49 +0,0 @@ -"""Deprecated functions, should be fine to remove.""" - - -async def add_services(hacs): - """Add services.""" - # Service registration - async def service_hacs_install(call): - """Install a repository.""" - repository = str(call.data["repository"]) - if repository not in hacs().store.repositories: - hacs.logger.error("%s is not a konwn repository!", repository) - return - repository = hacs().store.repositories[repository] - await repository.install() - - async def service_hacs_register(call): - """register a repository.""" - repository = call.data["repository"] - repository_type = call.data["repository_type"] - if await hacs().is_known_repository(repository): - hacs.logger.error("%s is already a konwn repository!", repository) - return - await hacs().register_new_repository(repository_type, repository) - - async def service_hacs_load(call): - """register a repository.""" - from homeassistant.loader import async_get_custom_components - - del hacs.hass.data["custom_components"] - await async_get_custom_components(hacs.hass) - - hacs.hass.services.async_register("hacs", "install", service_hacs_install) - hacs.hass.services.async_register("hacs", "register", service_hacs_register) - hacs.hass.services.async_register("hacs", "load", service_hacs_load) - - -# This should probably be in a dedicated test "package" -async def test_repositories(hacs): - """Test repositories.""" - await hacs().register_repository("ludeeus/theme-hacs", "theme") - await hacs().register_repository("ludeeus/ps-hacs", "python_script") - await hacs().register_repository("ludeeus/integration-hacs", "integration") - await hacs().register_repository( - "rgruebel/ha_zigbee2mqtt_networkmap", "integration" - ) - await hacs().register_repository("ludeeus/ad-hacs", "appdaemon") - await hacs().register_repository("jonkristian/entur-card", "plugin") # Dist - await hacs().register_repository("kalkih/mini-media-player", "plugin") # Release - await hacs().register_repository("custom-cards/monster-card", "plugin") # root diff --git a/hass/settings/custom_components/hacs/frontend/__init__.py b/hass/settings/custom_components/hacs/frontend/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/hass/settings/custom_components/hacs/frontend/elements/all.min.css.gz b/hass/settings/custom_components/hacs/frontend/elements/all.min.css.gz deleted file mode 100644 index 4d22287..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/all.min.css.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/hacs.css b/hass/settings/custom_components/hacs/frontend/elements/hacs.css deleted file mode 100644 index 2cf3259..0000000 --- a/hass/settings/custom_components/hacs/frontend/elements/hacs.css +++ /dev/null @@ -1,504 +0,0 @@ -.yaml { - font-family: monospace, monospace; - font-size: 1em; - border-style: solid; - border-width: thin; - margin: 0; - overflow: auto; - display: inline-flex; - width: calc(100% - 20px); - white-space: pre-wrap; -} - -.hacslist { - border: none; -} - -.hacs-card-container { - display: grid; - grid-gap: 10px; -} - -.hacs-overview-container { - width: 95%; - margin-left: 2.5%; - margin-right: 2.5%; - margin-bottom: 10px; - display: inline-block; -} - -.hacs-form { - display: contents; -} - -.hacs-table { - background-color: var(--paper-card-background-color); -} - -.hacs-content { - position: absolute; - top: 49px; - left: 0px; - right: 0px; - bottom: 0px; - overflow-y: auto; - overflow-x: hidden; - padding-top: 20px; - padding-bottom: 15px; -} - -.hacs-card { - height: 100%; - background-color: var(--paper-card-background-color) !important; - padding: 3px; - line-height: 1; -} - -.overview { - height: 100%; -} - -.progressbar { - margin-left: 2.5%; - margin-right: 2.5%; - margin-bottom: 20px; -} - -.hacs-card-title { - font-size: medium; - color: var(--primary-text-color); -} - -tr.hacs-table-row.repository { - border-bottom: 0px; - display: table-row-group; -} - -td.repository { - width: 50%; - padding: 0px; -} -td.repository.text { - padding-left: 12px; -} - - -select.hacs-select.repository { - width: 100%; -} -.hacs-card-content { - color: var(--secondary-text-color); - font-style: italic; - font-size: small; -} - -.card-status { - font-size: 18px; - padding-right: 4px; -} - -.hacs-card-standalone { - background-color: var(--paper-card-background-color) !important; - color: var(--primary-text-color); - padding: 16px; -} - -.installed { - color: var(--hacs-status-installed); -} - -.pending-restart { - color: var(--hacs-status-pending-restart); -} - -.pending-upgrade { - color: var(--hacs-status-pending-update); -} - -.default { - color: var(--primary-text-color); -} - -.hacs-nav { - background-color: var(--primary-color) !important; - position: fixed; - height: auto; -} - -a { - color: var(--primary-color); -} - -.disabledaction { - cursor: default; - color: var(--primary-color); - opacity: 0.5; -} - -.hacs-bar { - background-color: var(--primary-color) !important; -} -.hacs-bar-background { - background-color: var(--dark-primary-color) !important; -} - -.errorview { - display: block; - margin-bottom: 30px; -} - -.hacscolor { - background-color: var(--paper-card-background-color) !important; - color: var(--primary-text-color); -} - -.hacsbutton { - margin: 3%; - background-color: var(--primary-color) !important; -} - -.hacsadminbutton { - margin: 1%; - background-color: var(--primary-color) !important; -} - -body { - background-color: var(--primary-background-color) !important; - color: var(--primary-text-color); - overflow: hidden; - font-size: 14px; -} - -input[type="text"]:not(.browser-default):focus:not([readonly]) { - border-bottom: 1px solid var(--primary-color); - -webkit-box-shadow: 0 1px 0 0 var(--primary-color); - box-shadow: 0 1px 0 0 var(--primary-color); -} - -.dropdown-list-item { - color: var(--primary-color) !important; - background-color: var(--paper-card-background-color) !important; -} - -a.dropdown-list-item:hover { - opacity: 0.95; -} - -.actionlink { - color: var(--primary-color) !important -} - -.uninstall { - float: right; - color: var(--google-red-500) !important; - font-weight: bold; -} - -@media all and (max-width: 550px) { - select.hacs-select.custom_repository { - width: 100%; - } - input#custom_url { - width: 100% !important; - } - - .actionlink { - width: 100%; - padding: 5px; - display: block; - font-size: x-large; - text-align: center; - } - - .uninstall { - float: none; - } -} -.minigrid { - display: contents; -} - -.card-action a:hover { - opacity: 0.6 !important; -} - -.codeinfo { - opacity: 0.6 !important; -} - -.hacs-select { - display: initial !important; - margin-left: 1%; - width: 20%; - background-color: transparent; - border-color: transparent; - color: var(--primary-text-color); -} - -.hacs-badge { - background-color: var(--hacs-badge-color); - margin-right: 1%; - font-size: 12px; - padding: 0px 4px 2px 4px; - color: var(--hacs-badge-text-color); - -moz-border-radius: 10px 10px 10px 10px; - border-radius: 10px 10px 10px 10px; -} - -tr.hacs-table-row:hover { - cursor: pointer; -} - - -/* color vars*/ -:root { - --hacs-status-installed: #126e15; - --hacs-status-pending-restart: #a70000; - --hacs-status-pending-update: #ffab40; - --hacs-status-default: var(--primary-text-color); - --hacs-badge-color: var(--primary-color); - --hacs-badge-text-color: var(--primary-text-color); - --primary-color: #03a9f4; - --primary-text-color: #000000; - --secondary-text-color: #424141; - --primary-background-color: #fafafa; - --paper-card-background-color: #ffffff; - --dark-primary-color: #00405d; - --google-red-500: #db4437; -} - -/* hug screens*/ -@media all and (min-width: 2000px) { - .hacs-card-container { - grid-template-columns: repeat(6, 1fr); - } -} - -/* even bigger screens*/ -@media all and (min-width: 1500px) and (max-width: 1999px) { - .hacs-card-container { - grid-template-columns: repeat(5, 1fr); - } -} - -/* bigger screens*/ -@media all and (min-width: 1000px) and (max-width: 1499px) { - .hacs-card-container { - grid-template-columns: repeat(4, 1fr); - } -} - -/* big screens */ -@media all and (min-width: 550px) and (max-width: 999px) { - .hacs-card-container { - grid-template-columns: repeat(3, 1fr); - } - - - #main::-webkit-scrollbar-track - { - border-radius: 10px; - } - - #main::-webkit-scrollbar - { - width: 12px; - } - - #main::-webkit-scrollbar-thumb - { - border-radius: 10px; - background-color: var(--primary-color); - } -} - -/* smal screens */ -@media all and (max-width: 550px) { - body { - overflow: scroll !important; - } - - .minigrid { - display: grid; - } - - .smal-hide { - display: none !important; - } - - .hacs-content { - overflow: scroll !important; - -webkit-overflow-scrolling: touch; - } -} - - -/* laoder */ - -*.hidden { - display: none !important; -} - -div.loading{ - position: fixed; - z-index: 999; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(16, 16, 16, 0.5); -} - -@-webkit-keyframes uil-ring-anim { - 0% { - -ms-transform: rotate(0deg); - -moz-transform: rotate(0deg); - -webkit-transform: rotate(0deg); - -o-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -ms-transform: rotate(360deg); - -moz-transform: rotate(360deg); - -webkit-transform: rotate(360deg); - -o-transform: rotate(360deg); - transform: rotate(360deg); - } -} -@-webkit-keyframes uil-ring-anim { - 0% { - -ms-transform: rotate(0deg); - -moz-transform: rotate(0deg); - -webkit-transform: rotate(0deg); - -o-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -ms-transform: rotate(360deg); - -moz-transform: rotate(360deg); - -webkit-transform: rotate(360deg); - -o-transform: rotate(360deg); - transform: rotate(360deg); - } -} -@-moz-keyframes uil-ring-anim { - 0% { - -ms-transform: rotate(0deg); - -moz-transform: rotate(0deg); - -webkit-transform: rotate(0deg); - -o-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -ms-transform: rotate(360deg); - -moz-transform: rotate(360deg); - -webkit-transform: rotate(360deg); - -o-transform: rotate(360deg); - transform: rotate(360deg); - } -} -@-ms-keyframes uil-ring-anim { - 0% { - -ms-transform: rotate(0deg); - -moz-transform: rotate(0deg); - -webkit-transform: rotate(0deg); - -o-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -ms-transform: rotate(360deg); - -moz-transform: rotate(360deg); - -webkit-transform: rotate(360deg); - -o-transform: rotate(360deg); - transform: rotate(360deg); - } -} -@-moz-keyframes uil-ring-anim { - 0% { - -ms-transform: rotate(0deg); - -moz-transform: rotate(0deg); - -webkit-transform: rotate(0deg); - -o-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -ms-transform: rotate(360deg); - -moz-transform: rotate(360deg); - -webkit-transform: rotate(360deg); - -o-transform: rotate(360deg); - transform: rotate(360deg); - } -} -@-webkit-keyframes uil-ring-anim { - 0% { - -ms-transform: rotate(0deg); - -moz-transform: rotate(0deg); - -webkit-transform: rotate(0deg); - -o-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -ms-transform: rotate(360deg); - -moz-transform: rotate(360deg); - -webkit-transform: rotate(360deg); - -o-transform: rotate(360deg); - transform: rotate(360deg); - } -} -@-o-keyframes uil-ring-anim { - 0% { - -ms-transform: rotate(0deg); - -moz-transform: rotate(0deg); - -webkit-transform: rotate(0deg); - -o-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -ms-transform: rotate(360deg); - -moz-transform: rotate(360deg); - -webkit-transform: rotate(360deg); - -o-transform: rotate(360deg); - transform: rotate(360deg); - } -} -@keyframes uil-ring-anim { - 0% { - -ms-transform: rotate(0deg); - -moz-transform: rotate(0deg); - -webkit-transform: rotate(0deg); - -o-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -ms-transform: rotate(360deg); - -moz-transform: rotate(360deg); - -webkit-transform: rotate(360deg); - -o-transform: rotate(360deg); - transform: rotate(360deg); - } -} -.uil-ring-css { - margin: auto; - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - width: 200px; - height: 200px; -} -.uil-ring-css > div { - position: absolute; - display: block; - width: 160px; - height: 160px; - top: 20px; - left: 20px; - border-radius: 80px; - box-shadow: 0 6px 0 0 var(--primary-color); - -ms-animation: uil-ring-anim 1s linear infinite; - -moz-animation: uil-ring-anim 1s linear infinite; - -webkit-animation: uil-ring-anim 1s linear infinite; - -o-animation: uil-ring-anim 1s linear infinite; - animation: uil-ring-anim 1s linear infinite; -} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/elements/hacs.js b/hass/settings/custom_components/hacs/frontend/elements/hacs.js deleted file mode 100644 index 102a1bc..0000000 --- a/hass/settings/custom_components/hacs/frontend/elements/hacs.js +++ /dev/null @@ -1,111 +0,0 @@ -// Copy active HA theme -document.getElementsByTagName("html").item(0).setAttribute("style", parent.document.getElementsByTagName("html").item(0).style.cssText) - -// Copy yhe content of the Lovelace example to the clipboard. -function CopyToLovelaceExampleToClipboard() { - window.getSelection().selectAllChildren(document.getElementById("LovelaceExample")); - document.execCommand("copy"); - document.getSelection().empty() - document.getElementById('lovelacecopy').style.color = 'forestgreen'; -} - -// Show progress bar -function ShowProgressBar() { - document.getElementById('progressbar').style.display = 'block'; -} - -// Hard reloading -function HardReload() { - parent.location.reload(true) -} - -// Searchbar -function Search() { - var input = document.getElementById("Search"); - if (input) { - var filter = input.value.toLowerCase(); - var nodes = document.getElementsByClassName('hacs-card'); - for (var i = 0; i < nodes.length; i++) { - if (nodes[i].innerHTML.toLowerCase().includes(filter)) { - nodes[i].style.display = "block"; - } else { - nodes[i].style.display = "none"; - } - } - var nodes = document.getElementsByClassName('hacs-table-row'); - for (i = 0; i < nodes.length; i++) { - if (nodes[i].innerHTML.toLowerCase().includes(filter)) { - nodes[i].style.display = "table-row"; - } else { - nodes[i].style.display = "none"; - } - } - } -} - - -// Dropdown -document.addEventListener('DOMContentLoaded', function () { - var elems = document.querySelectorAll('.dropdown-trigger'); - M.Dropdown.init(elems, { hover: false, constrainWidth: false }); -}); - -// Modal -document.addEventListener('DOMContentLoaded', function () { - var elems = document.querySelectorAll('.modal'); - M.Modal.init(elems, {}); -}); - - -// Loader -function toggleLoading() { - var loadingOverlay = document.querySelector('.loading'); - loadingOverlay.classList.remove('hidden') - document.activeElement.blur(); -} - - -// Check if we can reload -function sleep(time) { - return new Promise((resolve) => setTimeout(resolve, time)); -} -function CheckIfWeCanReload() { - var data = true; - const hacsrequest = new XMLHttpRequest() - hacsrequest.open('GET', '/hacs_task', true) - hacsrequest.onload = function () { - data = JSON.parse(this.response) - data = data["task"] - if (!data) { - console.log("Background task is no longer running, reloading in 5s...") - sleep(5000).then(() => { - location.reload() - }); - } - } - hacsrequest.send() -} - -function IsTaskRunning() { - let retval = false; - let disp = document.getElementsByClassName("progress") - if (disp) { - disp = disp.item(0).style.display; - if (disp == "block") { - retval = true - } else { - retval = false - } - } - return retval -} - -window.setInterval(function () { - var running = false; - running = IsTaskRunning(); - if (running) { - CheckIfWeCanReload(); - } -}, 10000); - - diff --git a/hass/settings/custom_components/hacs/frontend/elements/materialize.min.css.gz b/hass/settings/custom_components/hacs/frontend/elements/materialize.min.css.gz deleted file mode 100644 index f7b1f50..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/materialize.min.css.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/materialize.min.js.gz b/hass/settings/custom_components/hacs/frontend/elements/materialize.min.js.gz deleted file mode 100644 index 10db151..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/materialize.min.js.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.eot.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.eot.gz deleted file mode 100644 index 9cb0839..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.eot.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.svg.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.svg.gz deleted file mode 100644 index 952de01..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.svg.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.ttf.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.ttf.gz deleted file mode 100644 index c3d423e..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.ttf.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.woff.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.woff.gz deleted file mode 100644 index fae25d3..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.woff.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.woff2.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.woff2.gz deleted file mode 100644 index f045d23..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-brands-400.woff2.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.eot.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.eot.gz deleted file mode 100644 index d7eb70f..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.eot.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.svg.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.svg.gz deleted file mode 100644 index da80623..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.svg.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.ttf.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.ttf.gz deleted file mode 100644 index a8876ed..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.ttf.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.woff.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.woff.gz deleted file mode 100644 index 8e35036..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.woff.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.woff2.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.woff2.gz deleted file mode 100644 index 7839668..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-regular-400.woff2.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.eot.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.eot.gz deleted file mode 100644 index 9872832..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.eot.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.svg.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.svg.gz deleted file mode 100644 index f7b5b3d..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.svg.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.ttf.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.ttf.gz deleted file mode 100644 index 20526ef..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.ttf.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.woff.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.woff.gz deleted file mode 100644 index 6b08ead..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.woff.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.woff2.gz b/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.woff2.gz deleted file mode 100644 index 3c0908a..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/elements/webfonts/fa-solid-900.woff2.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/experimental/main.js.gz b/hass/settings/custom_components/hacs/frontend/experimental/main.js.gz deleted file mode 100644 index aa04a5f..0000000 Binary files a/hass/settings/custom_components/hacs/frontend/experimental/main.js.gz and /dev/null differ diff --git a/hass/settings/custom_components/hacs/frontend/templates/base.html b/hass/settings/custom_components/hacs/frontend/templates/base.html deleted file mode 100644 index 561298a..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/base.html +++ /dev/null @@ -1,51 +0,0 @@ -{% set progressbar = 'block' if hacs.system.status.background_task else 'none' %} - - - - - - - - - - - - -
-
-
-

Background task running, this page will reload when it's done.

-
-
-
-
- - {% if message %} - {% include 'message.html' with context %} - {% endif %} - {% set hacs_repo = hacs.get_by_name("hacs/integration") %} - {% if hacs_repo.pending_restart %} - {% set message = "The frontend of HACS has been disabled until you restart Home Assistant." %} - {% include 'message.html' with context %} - {% else %} - {% block content %} - {% endblock %} - {% endif %} -
- - - diff --git a/hass/settings/custom_components/hacs/frontend/templates/error.html b/hass/settings/custom_components/hacs/frontend/templates/error.html deleted file mode 100644 index 7824de3..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/error.html +++ /dev/null @@ -1,4 +0,0 @@ -{% extends "base.html" %} -{% block content %} - -{% endblock %} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/grid.html b/hass/settings/custom_components/hacs/frontend/templates/grid.html deleted file mode 100644 index e0c3a62..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/grid.html +++ /dev/null @@ -1,36 +0,0 @@ - -
-
\ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/grid_new.html b/hass/settings/custom_components/hacs/frontend/templates/grid_new.html deleted file mode 100644 index b72c64a..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/grid_new.html +++ /dev/null @@ -1,47 +0,0 @@ -{% set repositories = namespace(repositories=[]) %} -{% for repository in hacs.sorted_by_name %} -{% if repository.status.new %} -{% set repositories.repositories = repositories.repositories+[repository] %} -{% endif %} -{% endfor %} -{% if repositories.repositories %} - -
-
-{% endif %} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/message.html b/hass/settings/custom_components/hacs/frontend/templates/message.html deleted file mode 100644 index d615a3d..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/message.html +++ /dev/null @@ -1,13 +0,0 @@ -
-
-
-
-
- - {{message}} - -
-
-
-
-
\ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/modal/upgrade_all.html b/hass/settings/custom_components/hacs/frontend/templates/modal/upgrade_all.html deleted file mode 100644 index 51c07d8..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/modal/upgrade_all.html +++ /dev/null @@ -1,33 +0,0 @@ - diff --git a/hass/settings/custom_components/hacs/frontend/templates/modal/wrong_ha_version.html b/hass/settings/custom_components/hacs/frontend/templates/modal/wrong_ha_version.html deleted file mode 100644 index baea02b..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/modal/wrong_ha_version.html +++ /dev/null @@ -1,12 +0,0 @@ - \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/overviews.html b/hass/settings/custom_components/hacs/frontend/templates/overviews.html deleted file mode 100644 index d66bfa5..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/overviews.html +++ /dev/null @@ -1,77 +0,0 @@ - -{% extends "base.html" %} -{% block content %} -{% if location == 'store' %} -
- -
-{% if hacs.configuration.frontend_mode == "Grid" %} -{% include 'grid_new.html' with context %} -{% else %} -{% include 'table_new.html' with context %} -{% endif %} -{% endif %} - -{% for type in hacs.common.categories %} - -{% if type == 'appdaemon' %} -{% set displaytype = 'APPDAEMON APPS' %} -{% elif type == 'python_script' %} -{% set displaytype = 'PYTHON SCRIPTS' %} -{% else %} -{% set displaytype = (type + 's') | upper %} -{% endif %} - -{% set repositories = namespace(repositories=[]) %} - -{% for repository in hacs.sorted_by_name %} -{% set repo = namespace(include=True) %} - -{% if repository.status.hide and repo.include %} -{% set repo.include = False %} -{% endif %} - -{% if repository.information.category != type and repo.include %} -{% set repo.include = False %} -{% endif %} - - -{% if location == 'overview' %} -{% if not repository.status.installed and repo.include %} -{% set repo.include = False %} -{% if repository.information.uid == "172733314" %} -{% set repo.include = True %} -{% endif %} -{% endif %} -{% else %} -{% if repository.information.uid == "172733314" %} -{% set repo.include = False %} -{% endif %} -{% if hacs.configuration.country and repo.include %} -{% if repository.repository_manifest %} -{% if repository.repository_manifest.country %} -{% if hacs.configuration.country not in repository.repository_manifest.country %} -{% set repo.include = False %} -{% endif %} -{% endif %} -{% endif %} -{% endif %} -{% endif %} - -{% if repo.include %} -{% set repositories.repositories = repositories.repositories+[repository] %} -{% endif %} -{% endfor %} - -{% if repositories.repositories %} -{% if hacs.configuration.frontend_mode == "Grid" %} -{% include 'grid.html' with context %} -{% else %} -{% include 'table.html' with context %} -{% endif %} -{% endif %} - -{% endfor %} - -{% endblock %} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/repository.html b/hass/settings/custom_components/hacs/frontend/templates/repository.html deleted file mode 100644 index 2a2dcd6..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/repository.html +++ /dev/null @@ -1,93 +0,0 @@ -{% extends "base.html" %} -{% block content %} - - -{% if repository.pending_restart %} -{% set message = "You need to restart (and potentially reconfigure) Home Assistant, for your last operation to be loaded." %} -{% endif %} - -{% if repository.information.category == "integration" and repository.status.first_install and repository.status.installed and repository.config_flow %} -{% set message = " - Good news!
- This integration supports config flows!
- This means that you can go to 'Configuration' --> 'Integrations' --> '+' to configure it.
- The best part if you do that, is that you do not need to restart Home Assistant.

- You may need to clear the cache on the integrations page before it shows in the list (+)."%} -{% endif %} - - -{% if message %} -{% include 'message.html' with context %} -{% endif %} - - -
-
-
-
-
- - {{repository.display_name}} - - - - - {% include 'repository/menu.html' with context %} - -

{{repository.information.description}}


- - {% if repository.status.installed %} - - - - {% endif %} - - - {% if repository.releases.published_tags %} - {% include 'repository/versionselect.html' with context %} - {% else %} - - - {% endif %} - - {% if repository.status.selected_tag == repository.information.default_branch %} - - - - - {% endif %} - {% include 'repository/authors.html' with context %} -
- Installed {{repository.display_version_or_commit}}: - - {{repository.display_installed_version}} -
- Available {{repository.display_version_or_commit}}: - - {{repository.display_available_version}} -
- Last updated: - - {{repository.information.last_updated}} -
-
- {% include 'repository/buttons.html' with context %} -
-
-
-
- -
-
-
-
-
- {{ repository.information.additional_info }} - {% include 'repository/note.html' with context %} -
-
-
-
-
-{% endblock %} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/repository/authors.html b/hass/settings/custom_components/hacs/frontend/templates/repository/authors.html deleted file mode 100644 index 5b0b192..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/repository/authors.html +++ /dev/null @@ -1,27 +0,0 @@ -{% if repository.information.authors %} -{% if repository.information.category == "integration" %} - - - Author(s): - - - {% for author in repository.information.authors %} - {% if "@" in author %} - {% set author = author.split("@")[-1] %} - {% endif %} - @{{author}} - {% endfor %} - - -{% else %} - - - Author: - - - {{repository.information.authors}} - - -{% endif %} -{% endif %} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/repository/buttons.html b/hass/settings/custom_components/hacs/frontend/templates/repository/buttons.html deleted file mode 100644 index e17097e..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/repository/buttons.html +++ /dev/null @@ -1,50 +0,0 @@ -{% if not repository.can_install %} -{% include 'modal/wrong_ha_version.html' with context %} -{% endif %} - -
- {% if repository.can_install %} -
- - - {{repository.main_action}} - -
- {% else %} - - {{repository.main_action}} - - {% endif %} - - {% if repository.pending_upgrade and repository.display_version_or_commit == "version" %} - - CHANGELOG - - {% endif %} - - - repository - - - {% if repository.status.installed and repository.information.category == "plugin" %} - {% set name = repository.information.full_name.split("/")[-1] %} - - OPEN PLUGIN - - {% endif %} - - {% if repository.status.installed and repository.information.uid != "172733314" %} -
- - - UNINSTALL - -
- {% endif %} - -
\ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/repository/menu.html b/hass/settings/custom_components/hacs/frontend/templates/repository/menu.html deleted file mode 100644 index 7104e99..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/repository/menu.html +++ /dev/null @@ -1,61 +0,0 @@ - \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/repository/note.html b/hass/settings/custom_components/hacs/frontend/templates/repository/note.html deleted file mode 100644 index edb8766..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/repository/note.html +++ /dev/null @@ -1,42 +0,0 @@ -{% if repository.additional_info %} -
-

-{% endif %} - -{% if repository.information.category == "appdaemon" %} - - - When installed, this will be located in '{{repository.content.path.local}}', - you still need to add it to your 'apps.yaml' file. - - -{% elif repository.information.category == "integration" %} - - - When installed, this will be located in '{{repository.content.path.local}}', - you still need to add it to your 'configuration.yaml' file. - - -{% elif repository.information.category == "plugin" %} -{% set name = repository.information.full_name.split("/")[-1] %} - - - When installed, this will be located in '{{repository.content.path.local }}', - you still need to add it to your lovelace configuration ('ui-lovelace.yaml' or the raw UI config editor). - -

- - When you add this to your configuration use this: -
-
-  - url: /community_plugin/{{name}}/{{repository.information.file_name}}
-  {%- if repository.information.javascript_type %}
-    type: {{repository.information.javascript_type}}
-  {%- else %}
-    type: Could not determine the type of this plugin, check the repository.
-  {%- endif -%}
-    
- - - -{% endif %} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/repository/versionselect.html b/hass/settings/custom_components/hacs/frontend/templates/repository/versionselect.html deleted file mode 100644 index 42a2b78..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/repository/versionselect.html +++ /dev/null @@ -1,24 +0,0 @@ -{% set tags = repository.releases.published_tags | sort(True) %} -{% set tags = tags + [repository.information.default_branch] %} - - -{% if repository.status.selected_tag %} -{% set selected_tag = repository.status.selected_tag %} -{% else %} -{% set selected_tag = repository.versions.available %} -{% endif %} - - Available versions: - - -
- - -
- \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/settings.html b/hass/settings/custom_components/hacs/frontend/templates/settings.html deleted file mode 100644 index 1d4f9ca..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/settings.html +++ /dev/null @@ -1,20 +0,0 @@ -{% extends "base.html" %} -{% block content %} -{% if hacs.configuration.dev %} -{% set message = "You have 'dev' enabled for HACS, this is not intended for regular use, no support will be given if you break something." %} -{% include 'message.html' with context %} -{% endif %} - -{% include 'modal/upgrade_all.html' with context %} - - -{% include 'settings/hacs_info.html' with context %} -{% include 'settings/buttons.html' with context %} -{% include 'settings/custom_repositories.html' with context %} -{% include 'settings/hidden_repositories.html' with context %} - - -{% if hacs.configuration.dev and not hacs.system.status.background_task %} -{% include 'settings/developer.html' with context %} -{% endif %} -{% endblock %} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/settings/buttons.html b/hass/settings/custom_components/hacs/frontend/templates/settings/buttons.html deleted file mode 100644 index 0db42a9..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/settings/buttons.html +++ /dev/null @@ -1,26 +0,0 @@ - \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/settings/custom_repositories.html b/hass/settings/custom_components/hacs/frontend/templates/settings/custom_repositories.html deleted file mode 100644 index 20a819e..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/settings/custom_repositories.html +++ /dev/null @@ -1,62 +0,0 @@ -
-
- - - {% if not hacs.system.status.background_task %} -
- - - - -
- {% endif %} -
-
\ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/settings/dev/remove_new_flag.html b/hass/settings/custom_components/hacs/frontend/templates/settings/dev/remove_new_flag.html deleted file mode 100644 index ac6f966..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/settings/dev/remove_new_flag.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends "base.html" %} -{% block content %} -
-
-
- -
-
-
-{% endblock %} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/settings/dev/repositories.html b/hass/settings/custom_components/hacs/frontend/templates/settings/dev/repositories.html deleted file mode 100644 index 91f598e..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/settings/dev/repositories.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "base.html" %} -{% block content %} -{% for repository in hacs.store.frontend|sort(attribute='name') %} -
- - -
-{% endfor %} -{% endblock %} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/settings/dev/repository.html b/hass/settings/custom_components/hacs/frontend/templates/settings/dev/repository.html deleted file mode 100644 index e69de29..0000000 diff --git a/hass/settings/custom_components/hacs/frontend/templates/settings/dev/set_ha_version.html b/hass/settings/custom_components/hacs/frontend/templates/settings/dev/set_ha_version.html deleted file mode 100644 index bda9fd8..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/settings/dev/set_ha_version.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "base.html" %} -{% block content %} -
-
-
- - -
-
-
-{% endblock %} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/settings/dev/template_test.html b/hass/settings/custom_components/hacs/frontend/templates/settings/dev/template_test.html deleted file mode 100644 index f89b786..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/settings/dev/template_test.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends "base.html" %} -{% block content %} -
-
-
- -
- - -
-
-
- -{% if hacs.dev_template %} -
-
- {{ hacs.dev_template }} -
-
-{% endif %} -{% endblock %} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/settings/dev/token.html b/hass/settings/custom_components/hacs/frontend/templates/settings/dev/token.html deleted file mode 100644 index a1ade04..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/settings/dev/token.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "base.html" %} -{% block content %} -
-
- -
-
-{% endblock %} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/settings/developer.html b/hass/settings/custom_components/hacs/frontend/templates/settings/developer.html deleted file mode 100644 index ee81e55..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/settings/developer.html +++ /dev/null @@ -1,19 +0,0 @@ -
-
-
DEVELOPER TOOLS
- {% for button in [ - "remove_new_flag", - "repositories", - "set_ha_version", - "token", - "template_test" - ] %} -
- - -
- {% endfor %} -
-
\ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/settings/hacs_info.html b/hass/settings/custom_components/hacs/frontend/templates/settings/hacs_info.html deleted file mode 100644 index c1851bd..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/settings/hacs_info.html +++ /dev/null @@ -1,38 +0,0 @@ -{% if hacs.get_by_id("172733314").pending_restart %} -{% set pending_restart = " (RESTART PENDING!)" %} -{% else %} -{% set pending_restart = "" %} -{% endif %} - -
-
-
HACS (Home Assistant Community Store)
- - - - - - - - - -
- Version: - - {{hacs.version}}{{pending_restart}} -
- Display: - -
- -
-
-
-
\ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/settings/hidden_repositories.html b/hass/settings/custom_components/hacs/frontend/templates/settings/hidden_repositories.html deleted file mode 100644 index 1e60f7b..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/settings/hidden_repositories.html +++ /dev/null @@ -1,42 +0,0 @@ -{% set repositories = namespace(hidden=False) %} -{% for repository in hacs.repositories_list_repo %} -{% if repository.hide %} -{% set repositories.hidden = True %} -{% endif %} -{% endfor %} - -{% if repositories.hidden %} -
-
-
    -
  • -
    HIDDEN REPOSITORIES
    -
  • - {% if hacs.system.status.background_task %} -
  • - Loading hidden repositories... -
  • - {% else %} - {% for repository in hacs.repositories_list_repo %} - {% if repository.hide %} -
  • -
    -
    - - - - - {{repository.repository_name}} - {{repository.repository_type}} -
    -
    -
  • - {% endif %} - {% endfor %} - {% endif %} -
-
-
-{% endif %} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/table.html b/hass/settings/custom_components/hacs/frontend/templates/table.html deleted file mode 100644 index 982afb1..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/table.html +++ /dev/null @@ -1,42 +0,0 @@ -
-
-
{{ displaytype }}
- - - - - - - {% if location == 'overview' %} - - - {% endif %} - - - - {% for repository in repositories.repositories %} - - - - - - {% endif %} - - - {% if location == 'overview' %} - - - {% endif %} - - {% endfor %} - -
StatusNameDescriptionInstalledAvailable
- {% if location == 'store' and repository.status.new %} - NEW - {% else %} - - {{repository.display_name}} - {{repository.information.description}}{{repository.display_installed_version}}{{repository.display_available_version}}
-
-
\ No newline at end of file diff --git a/hass/settings/custom_components/hacs/frontend/templates/table_new.html b/hass/settings/custom_components/hacs/frontend/templates/table_new.html deleted file mode 100644 index f87486d..0000000 --- a/hass/settings/custom_components/hacs/frontend/templates/table_new.html +++ /dev/null @@ -1,44 +0,0 @@ -{% set repositories = namespace(repositories=[]) %} -{% for repository in hacs.sorted_by_name %} -{% if repository.status.new %} -{% set repositories.repositories = repositories.repositories+[repository] %} -{% endif %} -{% endfor %} -{% if repositories.repositories %} -
-
-
NEW REPOSITORIES (ALL)
-
- - - Remove the NEW flag for all new items - -
- - - - - - - - - - {% for repository in repositories.repositories %} - - - - - - {% endfor %} - -
CategoryNameDescription
- {{repository.information.category | upper}} - - {{repository.display_name}} - {{repository.information.description}}
-
-
-{% endif %} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/hacsbase/__init__.py b/hass/settings/custom_components/hacs/hacsbase/__init__.py deleted file mode 100644 index cfe374b..0000000 --- a/hass/settings/custom_components/hacs/hacsbase/__init__.py +++ /dev/null @@ -1,391 +0,0 @@ -"""Initialize the HACS base.""" -# pylint: disable=unused-argument, bad-continuation -import json -import uuid -from datetime import timedelta - -from homeassistant.helpers.event import async_call_later, async_track_time_interval - -from aiogithubapi import AIOGitHubException, AIOGitHubRatelimit -from integrationhelper import Logger - - -from ..const import ELEMENT_TYPES -from ..store import async_load_from_store, async_save_to_store - - -class HacsStatus: - """HacsStatus.""" - - startup = False - background_task = False - reloading_data = False - upgrading_all = False - - -class HacsCommon: - """Common for HACS.""" - - categories = [] - blacklist = [] - default = [] - installed = [] - skip = [] - - -class System: - """System info.""" - - status = HacsStatus() - config_path = None - ha_version = None - disabled = False - - -class Developer: - """Developer settings/tools.""" - - template_id = "Repository ID" - template_content = "" - template_raw = "" - - @property - def devcontainer(self): - """Is it a devcontainer?""" - import os - - if "DEVCONTAINER" in os.environ: - return True - return False - - -class Hacs: - """The base class of HACS, nested thoughout the project.""" - - token = f"{str(uuid.uuid4())}-{str(uuid.uuid4())}" - hacsweb = f"/hacsweb/{token}" - hacsapi = f"/hacsapi/{token}" - repositories = [] - repo = None - data_repo = None - developer = Developer() - data = None - configuration = None - logger = Logger("hacs") - github = None - hass = None - version = None - system = System() - tasks = [] - common = HacsCommon() - - @staticmethod - def init(hass, github_token): - """Return a initialized HACS object.""" - return Hacs() - - def get_by_id(self, repository_id): - """Get repository by ID.""" - try: - for repository in self.repositories: - if repository.information.uid == repository_id: - return repository - except Exception: # pylint: disable=broad-except - pass - return None - - def get_by_name(self, repository_full_name): - """Get repository by full_name.""" - try: - for repository in self.repositories: - if repository.information.full_name == repository_full_name: - return repository - except Exception: # pylint: disable=broad-except - pass - return None - - def is_known(self, repository_full_name): - """Return a bool if the repository is known.""" - for repository in self.repositories: - if repository.information.full_name == repository_full_name: - return True - return False - - @property - def sorted_by_name(self): - """Return a sorted(by name) list of repository objects.""" - return sorted(self.repositories, key=lambda x: x.display_name) - - @property - def sorted_by_repository_name(self): - """Return a sorted(by repository_name) list of repository objects.""" - return sorted(self.repositories, key=lambda x: x.information.full_name) - - async def register_repository(self, full_name, category, check=True): - """Register a repository.""" - from ..repositories.repository import RERPOSITORY_CLASSES - - if full_name in self.common.skip: - if full_name != "hacs/integration": - self.logger.debug(f"Skipping {full_name}") - return - - if category not in RERPOSITORY_CLASSES: - self.logger.error(f"{category} is not a valid repository category.") - return False - - repository = RERPOSITORY_CLASSES[category](full_name) - if check: - try: - await repository.registration() - if repository.validate.errors: - self.common.skip.append(repository.information.full_name) - if not self.system.status.startup: - self.logger.error(f"Validation for {full_name} failed.") - return repository.validate.errors - repository.logger.info("Registration complete") - except AIOGitHubException as exception: - self.logger.debug(self.github.ratelimits.remaining) - self.logger.debug(self.github.ratelimits.reset_utc) - self.common.skip.append(repository.information.full_name) - if not self.system.status.startup: - self.logger.error( - f"Validation for {full_name} failed with {exception}." - ) - return exception - self.hass.bus.async_fire( - "hacs/repository", - { - "id": 1337, - "action": "registration", - "repository": repository.information.full_name, - "repository_id": repository.information.uid, - }, - ) - self.repositories.append(repository) - - async def startup_tasks(self): - """Tasks tha are started after startup.""" - self.system.status.background_task = True - self.hass.bus.async_fire("hacs/status", {}) - self.logger.debug(self.github.ratelimits.remaining) - self.logger.debug(self.github.ratelimits.reset_utc) - - await self.handle_critical_repositories_startup() - await self.handle_critical_repositories() - await self.load_known_repositories() - await self.clear_out_blacklisted_repositories() - - self.tasks.append( - async_track_time_interval( - self.hass, self.recuring_tasks_installed, timedelta(minutes=30) - ) - ) - self.tasks.append( - async_track_time_interval( - self.hass, self.recuring_tasks_all, timedelta(minutes=800) - ) - ) - - self.system.status.startup = False - self.system.status.background_task = False - self.hass.bus.async_fire("hacs/status", {}) - await self.data.async_write() - - async def handle_critical_repositories_startup(self): - """Handled critical repositories during startup.""" - alert = False - critical = await async_load_from_store(self.hass, "critical") - if not critical: - return - for repo in critical: - if not repo["acknowledged"]: - alert = True - if alert: - self.logger.critical("URGENT!: Check the HACS panel!") - self.hass.components.persistent_notification.create( - title="URGENT!", message="**Check the HACS panel!**" - ) - - async def handle_critical_repositories(self): - """Handled critical repositories during runtime.""" - # Get critical repositories - instored = [] - critical = [] - was_installed = False - - try: - critical = await self.data_repo.get_contents("critical") - critical = json.loads(critical.content) - except AIOGitHubException: - pass - - if not critical: - self.logger.debug("No critical repositories") - return - - stored_critical = await async_load_from_store(self.hass, "critical") - - for stored in stored_critical or []: - instored.append(stored["repository"]) - - stored_critical = [] - - for repository in critical: - self.common.blacklist.append(repository["repository"]) - repo = self.get_by_name(repository["repository"]) - - stored = { - "repository": repository["repository"], - "reason": repository["reason"], - "link": repository["link"], - "acknowledged": True, - } - - if repository["repository"] not in instored: - if repo is not None and repo.installed: - self.logger.critical( - f"Removing repository {repository['repository']}, it is marked as critical" - ) - was_installed = True - stored["acknowledged"] = False - # Uninstall from HACS - repo.remove() - await repo.uninstall() - stored_critical.append(stored) - - # Save to FS - await async_save_to_store(self.hass, "critical", stored_critical) - - # Resart HASS - if was_installed: - self.logger.critical("Resarting Home Assistant") - self.hass.async_create_task(self.hass.async_stop(100)) - - async def recuring_tasks_installed(self, notarealarg=None): - """Recuring tasks for installed repositories.""" - self.logger.debug( - "Starting recuring background task for installed repositories" - ) - self.system.status.background_task = True - self.hass.bus.async_fire("hacs/status", {}) - self.logger.debug(self.github.ratelimits.remaining) - self.logger.debug(self.github.ratelimits.reset_utc) - for repository in self.repositories: - if repository.status.installed: - try: - await repository.update_repository() - repository.logger.debug("Information update done.") - except AIOGitHubException: - self.system.status.background_task = False - self.hass.bus.async_fire("hacs/status", {}) - await self.data.async_write() - self.logger.debug( - "Recuring background task for installed repositories done" - ) - return - await self.handle_critical_repositories() - self.system.status.background_task = False - self.hass.bus.async_fire("hacs/status", {}) - await self.data.async_write() - self.logger.debug("Recuring background task for installed repositories done") - - async def recuring_tasks_all(self, notarealarg=None): - """Recuring tasks for all repositories.""" - self.logger.debug("Starting recuring background task for all repositories") - self.system.status.background_task = True - self.hass.bus.async_fire("hacs/status", {}) - self.logger.debug(self.github.ratelimits.remaining) - self.logger.debug(self.github.ratelimits.reset_utc) - for repository in self.repositories: - try: - await repository.update_repository() - repository.logger.debug("Information update done.") - except AIOGitHubException: - self.system.status.background_task = False - self.hass.bus.async_fire("hacs/status", {}) - await self.data.async_write() - self.logger.debug("Recuring background task for all repositories done") - return - await self.load_known_repositories() - await self.clear_out_blacklisted_repositories() - self.system.status.background_task = False - await self.data.async_write() - self.hass.bus.async_fire("hacs/status", {}) - self.hass.bus.async_fire("hacs/repository", {"action": "reload"}) - self.logger.debug("Recuring background task for all repositories done") - - async def clear_out_blacklisted_repositories(self): - """Clear out blaclisted repositories.""" - need_to_save = False - for repository in self.common.blacklist: - if self.is_known(repository): - repository = self.get_by_name(repository) - if repository.status.installed: - self.logger.error( - f"You have {repository.information.full_name} installed with HACS, this repositroy has been blacklisted, please consider removing it." - ) - else: - need_to_save = True - repository.remove() - - if need_to_save: - await self.data.async_write() - - async def get_repositories(self): - """Return a list of repositories.""" - repositories = {} - if self.configuration.dev: - if self.developer.devcontainer: - repositories = { - "appdaemon": ["ludeeus/ad-hacs"], - "integration": ["ludeeus/integration-hacs"], - "plugin": ["maykar/compact-custom-header"], - "python_script": ["ludeeus/ps-hacs"], - "theme": ["ludeeus/theme-hacs"], - } - else: - for category in self.common.categories: - remote = await self.data_repo.get_contents(category) - repositories[category] = json.loads(remote.content) - if category == "plugin": - org = await self.github.get_org_repos("custom-cards") - for repo in org: - repositories[category].append(repo.full_name) - if category == "integration": - org = await self.github.get_org_repos("custom-components") - for repo in org: - repositories[category].append(repo.full_name) - if category == "theme": - org = await self.github.get_org_repos( - "home-assistant-community-themes" - ) - for repo in org: - repositories[category].append(repo.full_name) - - for category in repositories: - for repo in repositories[category]: - if repo not in self.common.default: - self.common.default.append(repo) - return repositories - - async def load_known_repositories(self): - """Load known repositories.""" - self.logger.info("Loading known repositories") - blacklist = await self.data_repo.get_contents("blacklist") - repositories = await self.get_repositories() - - for item in json.loads(blacklist.content): - if item not in self.common.blacklist: - self.common.blacklist.append(item) - - for category in repositories: - for repo in repositories[category]: - if repo in self.common.blacklist: - continue - if self.is_known(repo): - continue - try: - await self.register_repository(repo, category) - except (AIOGitHubException, AIOGitHubRatelimit): - pass diff --git a/hass/settings/custom_components/hacs/hacsbase/backup.py b/hass/settings/custom_components/hacs/hacsbase/backup.py deleted file mode 100644 index 2702dcc..0000000 --- a/hass/settings/custom_components/hacs/hacsbase/backup.py +++ /dev/null @@ -1,72 +0,0 @@ -"""Backup.""" -import os -import shutil -import tempfile -from time import sleep - -from integrationhelper import Logger - -BACKUP_PATH = tempfile.gettempdir() + "/hacs_backup/" - - -class Backup: - """Backup.""" - - def __init__(self, local_path, backup_path=BACKUP_PATH): - """initialize.""" - self.logger = Logger("hacs.backup") - self.local_path = local_path - self.backup_path = backup_path - self.backup_path_full = f"{self.backup_path}{self.local_path.split('/')[-1]}" - - def create(self): - """Create a backup in /tmp""" - if not os.path.exists(self.local_path): - return - if os.path.exists(self.backup_path): - shutil.rmtree(self.backup_path) - while os.path.exists(self.backup_path): - sleep(0.1) - os.makedirs(self.backup_path, exist_ok=True) - - try: - if os.path.isfile(self.local_path): - shutil.copyfile(self.local_path, self.backup_path_full) - os.remove(self.local_path) - else: - shutil.copytree(self.local_path, self.backup_path_full) - shutil.rmtree(self.local_path) - while os.path.exists(self.local_path): - sleep(0.1) - self.logger.debug( - f"Backup for {self.local_path}, created in {self.backup_path_full}" - ) - except Exception: # pylint: disable=broad-except - pass - - def restore(self): - """Restore from backup.""" - if not os.path.exists(self.backup_path_full): - return - - if os.path.isfile(self.backup_path_full): - if os.path.exists(self.local_path): - os.remove(self.local_path) - shutil.copyfile(self.backup_path_full, self.local_path) - else: - if os.path.exists(self.local_path): - shutil.rmtree(self.local_path) - while os.path.exists(self.local_path): - sleep(0.1) - shutil.copytree(self.backup_path_full, self.local_path) - self.logger.debug( - f"Restored {self.local_path}, from backup {self.backup_path_full}" - ) - - def cleanup(self): - """Cleanup backup files.""" - if os.path.exists(self.backup_path): - shutil.rmtree(self.backup_path) - while os.path.exists(self.backup_path): - sleep(0.1) - self.logger.debug(f"Backup dir {self.backup_path} cleared") diff --git a/hass/settings/custom_components/hacs/hacsbase/configuration.py b/hass/settings/custom_components/hacs/hacsbase/configuration.py deleted file mode 100644 index 6d81be3..0000000 --- a/hass/settings/custom_components/hacs/hacsbase/configuration.py +++ /dev/null @@ -1,55 +0,0 @@ -"""HACS Configuration.""" -import attr - -from custom_components.hacs.hacsbase.exceptions import HacsUserScrewupException - - -@attr.s(auto_attribs=True) -class Configuration: - """Configuration class.""" - - # Main configuration: - appdaemon_path: str = "appdaemon/apps/" - appdaemon: bool = False - config: dict = {} - config_entry: dict = {} - config_type: str = None - dev: bool = False - frontend_mode: str = "Grid" - options: dict = {} - plugin_path: str = "www/community/" - python_script_path: str = "python_scripts/" - python_script: bool = False - sidepanel_icon: str = "mdi:alpha-c-box" - sidepanel_title: str = "Community" - theme_path: str = "themes/" - theme: bool = False - token: str = None - - # Config options: - country: str = "ALL" - experimental: bool = False - release_limit: int = 5 - - @staticmethod - def from_dict(configuration: dict, options: dict): - """Set attributes from dicts.""" - if isinstance(options, bool) or isinstance(configuration.get("options"), bool): - raise HacsUserScrewupException("Configuration is not valid.") - - if options is None: - options = {} - - if not configuration: - raise HacsUserScrewupException("Configuration is not valid.") - - config = Configuration() - - config.config = configuration - config.options = options - - for conf_type in [configuration, options]: - for key in conf_type: - setattr(config, key, conf_type[key]) - - return config diff --git a/hass/settings/custom_components/hacs/hacsbase/const.py b/hass/settings/custom_components/hacs/hacsbase/const.py deleted file mode 100644 index 1e72154..0000000 --- a/hass/settings/custom_components/hacs/hacsbase/const.py +++ /dev/null @@ -1,10 +0,0 @@ -"""Constants for HACS""" -# pylint: disable=unused-import -STORAGE_VERSION = "6" -STORENAME = "hacs" - -# Messages -NOT_SUPPORTED_HA_VERSION = "You have version '{}' of Home Assistant, but version '{}' of '{}' require version '{}' of Home Assistant, install and upgrades are disabled for this integration untill you upgrade Home Assistant." - - -NO_ELEMENTS = "No elements to show, open the store to install some awesome stuff." diff --git a/hass/settings/custom_components/hacs/hacsbase/data.py b/hass/settings/custom_components/hacs/hacsbase/data.py deleted file mode 100644 index 1521ee4..0000000 --- a/hass/settings/custom_components/hacs/hacsbase/data.py +++ /dev/null @@ -1,215 +0,0 @@ -"""Data handler for HACS.""" -import os -import json -from integrationhelper import Logger -from . import Hacs -from .const import STORAGE_VERSION -from ..const import VERSION -from ..repositories.manifest import HacsManifest -from ..store import async_save_to_store, async_load_from_store - - -STORES = { - "old": "hacs", - "hacs": "hacs.hacs", - "installed": "hacs.installed", - "repositories": "hacs.repositories", -} - - -class HacsData(Hacs): - """HacsData class.""" - - def __init__(self): - """Initialize.""" - self.logger = Logger("hacs.data") - - def check_corrupted_files(self): - """Return True if one (or more) of the files are corrupted.""" - for store in STORES: - path = f"{self.system.config_path}/.storage/{STORES[store]}" - if os.path.exists(path): - if os.stat(path).st_size == 0: - # File is empty (corrupted) - return True - return False - - def read(self, store): - """Return data from a store.""" - path = f"{self.system.config_path}/.storage/{STORES[store]}" - content = None - if os.path.exists(path): - with open(path, "r", encoding="utf-8") as storefile: - content = storefile.read() - content = json.loads(content) - return content - - async def async_write(self): - """Write content to the store files.""" - if self.system.status.background_task: - return - - self.logger.debug("Saving data") - - # Hacs - await async_save_to_store( - self.hass, "hacs", {"view": self.configuration.frontend_mode} - ) - - # Repositories - content = {} - for repository in self.repositories: - if repository.repository_manifest is not None: - repository_manifest = repository.repository_manifest.manifest - else: - repository_manifest = None - content[repository.information.uid] = { - "authors": repository.information.authors, - "topics": repository.information.topics, - "category": repository.information.category, - "description": repository.information.description, - "full_name": repository.information.full_name, - "hide": repository.status.hide, - "installed_commit": repository.versions.installed_commit, - "installed": repository.status.installed, - "last_commit": repository.versions.available_commit, - "last_release_tag": repository.versions.available, - "repository_manifest": repository_manifest, - "name": repository.information.name, - "new": repository.status.new, - "selected_tag": repository.status.selected_tag, - "show_beta": repository.status.show_beta, - "version_installed": repository.versions.installed, - } - - await async_save_to_store(self.hass, "repositories", content) - self.hass.bus.async_fire("hacs/repository", {}) - self.hass.bus.fire("hacs/config", {}) - - async def restore(self): - """Restore saved data.""" - hacs = {} - repositories = {} - - try: - hacs = await async_load_from_store(self.hass, "hacs") - except KeyError: - await async_save_to_store(self.hass, "hacs", self.data.read("hacs")["data"]) - hacs = await async_load_from_store(self.hass, "hacs") - - try: - repositories = await async_load_from_store(self.hass, "repositories") - except KeyError: - await async_save_to_store( - self.hass, "repositories", self.data.read("repositories")["data"] - ) - repositories = await async_load_from_store(self.hass, "repositories") - - try: - if self.check_corrupted_files(): - # Coruptted installation - self.logger.critical("Restore failed one or more files are corrupted!") - return False - if hacs is None and repositories is None: - # Assume new install - return True - - self.logger.info("Restore started") - - # Hacs - self.configuration.frontend_mode = hacs.get("view", "Grid") - - # Repositories - repositories = repositories - for entry in repositories: - repo = repositories[entry] - if repo["full_name"] == "custom-components/hacs": - # Skip the old repo location - continue - if not self.is_known(repo["full_name"]): - await self.register_repository( - repo["full_name"], repo["category"], False - ) - repository = self.get_by_name(repo["full_name"]) - if repository is None: - self.logger.error(f"Did not find {repo['full_name']}") - continue - - # Restore repository attributes - if repo.get("authors") is not None: - repository.information.authors = repo["authors"] - - if repo.get("topics", []): - repository.information.topics = repo["topics"] - - if repo.get("description") is not None: - repository.information.description = repo["description"] - - if repo.get("name") is not None: - repository.information.name = repo["name"] - - if repo.get("hide") is not None: - repository.status.hide = repo["hide"] - - if repo.get("installed") is not None: - repository.status.installed = repo["installed"] - if repository.status.installed: - repository.status.first_install = False - - if repo.get("selected_tag") is not None: - repository.status.selected_tag = repo["selected_tag"] - - if repo.get("repository_manifest") is not None: - repository.repository_manifest = HacsManifest.from_dict( - repo["repository_manifest"] - ) - - if repo.get("show_beta") is not None: - repository.status.show_beta = repo["show_beta"] - - if repo.get("last_commit") is not None: - repository.versions.available_commit = repo["last_commit"] - - repository.information.uid = entry - - if repo.get("last_release_tag") is not None: - repository.releases.last_release = repo["last_release_tag"] - repository.versions.available = repo["last_release_tag"] - - if repo.get("new") is not None: - repository.status.new = repo["new"] - - if repo["full_name"] == "hacs/integration": - repository.versions.installed = VERSION - repository.status.installed = True - if "b" in VERSION: - repository.status.show_beta = True - elif repo.get("version_installed") is not None: - repository.versions.installed = repo["version_installed"] - - if repo.get("installed_commit") is not None: - repository.versions.installed_commit = repo["installed_commit"] - - self.logger.info("Restore done") - except Exception as exception: - self.logger.critical( - f"[{exception}] Restore Failed! see https://github.com/hacs/integration/issues/639 for more details." - ) - return False - return True - - -def save(logger, path, content): - """Save file.""" - from .backup import Backup - - backup = Backup(path) - backup.create() - try: - content = {"data": content, "schema": STORAGE_VERSION} - with open(path, "w", encoding="utf-8") as storefile: - json.dump(content, storefile, indent=4) - except Exception as exception: # pylint: disable=broad-except - logger.warning(f"Saving {path} failed - {exception}") - backup.restore() - backup.cleanup() diff --git a/hass/settings/custom_components/hacs/hacsbase/exceptions.py b/hass/settings/custom_components/hacs/hacsbase/exceptions.py deleted file mode 100644 index 48ab086..0000000 --- a/hass/settings/custom_components/hacs/hacsbase/exceptions.py +++ /dev/null @@ -1,45 +0,0 @@ -"""Custom Exceptions.""" - - -class HacsBaseException(Exception): - """Super basic.""" - - -class HacsUserScrewupException(HacsBaseException): - """Raise this when the user does something they should not do.""" - - -class HacsNotSoBasicException(HacsBaseException): - """Not that basic.""" - - -class HacsDataFileMissing(HacsBaseException): - """Raise this storage datafile is missing.""" - - -class HacsDataNotExpected(HacsBaseException): - """Raise this when data returned from storage is not ok.""" - - -class HacsRepositoryInfo(HacsBaseException): - """Raise this when repository info is missing/wrong.""" - - -class HacsRequirement(HacsBaseException): - """Raise this when repository is missing a requirement.""" - - -class HacsMissingManifest(HacsBaseException): - """Raise this when manifest is missing.""" - - def __init__(self, message="The manifest file is missing in the repository."): - super().__init__(message) - self.message = message - - -class HacsBlacklistException(HacsBaseException): - """Raise this when the repository is currently in the blacklist.""" - - def __init__(self, message="The repository is currently in the blacklist."): - super().__init__(message) - self.message = message diff --git a/hass/settings/custom_components/hacs/hacsbase/migration.py b/hass/settings/custom_components/hacs/hacsbase/migration.py deleted file mode 100644 index a2feb14..0000000 --- a/hass/settings/custom_components/hacs/hacsbase/migration.py +++ /dev/null @@ -1,129 +0,0 @@ -"""HACS Migration logic.""" -# pylint: disable=broad-except,no-member -from shutil import copy2 - -from integrationhelper import Logger, Validate - -from . import Hacs -from .data import save, STORES -from .const import STORAGE_VERSION - - -MIGRATIONS = {} - - -def register(cls): - """Register steps.""" - MIGRATIONS[cls.from_version] = cls - return cls - - -class ValidateData(Hacs): - """Validate.""" - - def validate_local_data_file(self): - """Validate content.""" - validate = Validate() - old_data = self.data.read("old") - - if old_data is None: - # new install. - return True - - if old_data.get("hacs", {}).get("schema") is None: - return True - - if old_data.get("hacs", {}).get("schema") == STORAGE_VERSION: - # Newest version, no need to do anything. - return - - current = old_data.get("hacs", {}).get("schema") - - for version in range(int(current), int(STORAGE_VERSION)): - if current in MIGRATIONS: - MIGRATIONS[current](old_data).migrate() - else: - validate.errors.append(f"Missing migration step for {version}") - - if validate.errors: - for error in validate.errors: - self.logger.critical(error) - return validate.success - - -class Migration(Hacs): - """Hacs migrations""" - - def __init__(self, old_data=None): - """initialize migration.""" - self.old_data = old_data - self.logger = Logger("hacs.migration") - self.source = f"{self.system.config_path}/.storage/hacs" - self.cleanup() - self.backup() - - def cleanup(self): - """Remove files no longer in use.""" - - def backup(self): - """Back up old file.""" - destination = f"{self.source}.{self.from_version}" - self.logger.info(f"Backing up current file to '{destination}'") - copy2(self.source, destination) - - -@register -class FromVersion4(Migration): - """Migrate from version 4""" - - from_version = "4" - - def migrate(self): - """Start migration.""" - self.logger.info(f"Starting migration from {self.from_version}") - hacs = self.old_data["hacs"] - repositories = self.old_data["repositories"] - installed = {} - - for repository in repositories: - repository = repositories[repository] - repository["full_name"] = repository["repository_name"] - repository["category"] = repository["repository_type"] - if not repository["installed"]: - repository["show_beta"] = False - else: - if repository["version_installed"] is not None: - version_type = "version" - version_installed = repository["version_installed"] - version_available = repository["last_release_tag"] - else: - version_type = "commit" - version_installed = repository["installed_commit"] - version_available = repository["last_commit"] - if repository["full_name"] != "hacs/integration": - installed[repository["repository_name"]] = { - "version_type": str(version_type), - "version_installed": str(version_installed), - "version_available": str(version_available), - } - - path = f"{self.system.config_path}/.storage/{STORES['hacs']}" - save(self.logger, path, hacs) - - path = f"{self.system.config_path}/.storage/{STORES['repositories']}" - save(self.logger, path, repositories) - - path = f"{self.system.config_path}/.storage/{STORES['installed']}" - save(self.logger, path, installed) - self.logger.info("Migration done") - - -@register -class FromVersion5(Migration): - """Migrate from version 5""" - - from_version = "5" - - def migrate(self): - """Start migration.""" - self.logger.info("Migration done") diff --git a/hass/settings/custom_components/hacs/hacsbase/startup.py b/hass/settings/custom_components/hacs/hacsbase/startup.py deleted file mode 100644 index b936b97..0000000 --- a/hass/settings/custom_components/hacs/hacsbase/startup.py +++ /dev/null @@ -1,16 +0,0 @@ -"""HACS Startup.""" -from . import Hacs - - -class HacsStartup(Hacs): - """Startup class.""" - - async def run_startup(self): - """Run startup tasks for HACS.""" - self.logger.critical("Startup!") - if self.configuration.dev: - self.logger.critical("Running in DEV mode!") - if self.developer.devcontainer: - self.logger.critical("Running inside a devcontainer") - self.logger.critical("Some features have been disabled") - self.logger.critical("It will only fetch one repository pr category") diff --git a/hass/settings/custom_components/hacs/hacsbase/update.py b/hass/settings/custom_components/hacs/hacsbase/update.py deleted file mode 100644 index dda5f3d..0000000 --- a/hass/settings/custom_components/hacs/hacsbase/update.py +++ /dev/null @@ -1,6 +0,0 @@ -"""HACS Updater.""" -from . import Hacs - - -class HacsUpdate(Hacs): - """Update class.""" diff --git a/hass/settings/custom_components/hacs/handler/__init__.py b/hass/settings/custom_components/hacs/handler/__init__.py deleted file mode 100644 index ab064c7..0000000 --- a/hass/settings/custom_components/hacs/handler/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Initialize handlers.""" diff --git a/hass/settings/custom_components/hacs/handler/download.py b/hass/settings/custom_components/hacs/handler/download.py deleted file mode 100644 index 385db21..0000000 --- a/hass/settings/custom_components/hacs/handler/download.py +++ /dev/null @@ -1,78 +0,0 @@ -"""Download.""" -import os -import gzip -import shutil - -import aiofiles -import async_timeout -from integrationhelper import Logger -import backoff -from homeassistant.helpers.aiohttp_client import async_get_clientsession -from ..hacsbase.exceptions import HacsNotSoBasicException - - -@backoff.on_exception(backoff.expo, Exception, max_tries=5) -async def async_download_file(hass, url): - """ - Download files, and return the content. - """ - logger = Logger("hacs.download.downloader") - if url is None: - return - - # There is a bug somewhere... TODO: Find that bug.... - if "tags/" in url: - url = url.replace("tags/", "") - - logger.debug(f"Donwloading {url}") - - result = None - - with async_timeout.timeout(60, loop=hass.loop): - request = await async_get_clientsession(hass).get(url) - - # Make sure that we got a valid result - if request.status == 200: - result = await request.read() - else: - raise HacsNotSoBasicException( - "Got status code {} when trying to download {}".format( - request.status, url - ) - ) - - return result - - -async def async_save_file(location, content): - """Save files.""" - logger = Logger("hacs.download.save") - logger.debug(f"Saving {location}") - mode = "w" - encoding = "utf-8" - errors = "ignore" - - if not isinstance(content, str): - mode = "wb" - encoding = None - errors = None - - try: - async with aiofiles.open( - location, mode=mode, encoding=encoding, errors=errors - ) as outfile: - await outfile.write(content) - outfile.close() - - # Create gz for .js files - if os.path.isfile(location): - if location.endswith(".js") or location.endswith(".css"): - with open(location, "rb") as f_in: - with gzip.open(location + ".gz", "wb") as f_out: - shutil.copyfileobj(f_in, f_out) - - except Exception as error: # pylint: disable=broad-except - msg = "Could not write data to {} - {}".format(location, error) - logger.debug(msg) - - return os.path.exists(location) diff --git a/hass/settings/custom_components/hacs/handler/template.py b/hass/settings/custom_components/hacs/handler/template.py deleted file mode 100644 index ca77e7a..0000000 --- a/hass/settings/custom_components/hacs/handler/template.py +++ /dev/null @@ -1,29 +0,0 @@ -"""Custom template support.""" -# pylint: disable=broad-except -from jinja2 import Template -from integrationhelper import Logger - - -def render_template(content, context): - """Render templates in content.""" - # Fix None issues - if context.releases.last_release_object is not None: - prerelease = context.releases.last_release_object.prerelease - else: - prerelease = False - - # Render the template - try: - render = Template(content) - render = render.render( - installed=context.status.installed, - pending_update=context.pending_upgrade, - prerelease=prerelease, - selected_tag=context.status.selected_tag, - version_available=context.releases.last_release, - version_installed=context.display_installed_version, - ) - return render - except Exception as exception: - Logger("hacs.template").debug(exception) - return content diff --git a/hass/settings/custom_components/hacs/helpers/misc.py b/hass/settings/custom_components/hacs/helpers/misc.py deleted file mode 100644 index 19d6a40..0000000 --- a/hass/settings/custom_components/hacs/helpers/misc.py +++ /dev/null @@ -1,27 +0,0 @@ -"""Helper functions: misc""" -import semantic_version - - -def get_repository_name( - hacs_manifest, repository_name: str, category: str = None, manifest: dict = None -) -> str: - """Return the name of the repository for use in the frontend.""" - - if hacs_manifest.name is not None: - return hacs_manifest.name - - if category == "integration": - if manifest: - if "name" in manifest: - return manifest["name"] - - return repository_name.replace("-", " ").replace("_", " ").title() - - -def version_is_newer_than_version(new: str, old: str) -> bool: - """Return a bool if source is newer than target, will also be true if identical.""" - if not isinstance(new, str) or not isinstance(old, str): - return False - if new == old: - return True - return semantic_version.Version.coerce(new) > semantic_version.Version.coerce(old) diff --git a/hass/settings/custom_components/hacs/http.py b/hass/settings/custom_components/hacs/http.py deleted file mode 100644 index db0dfaa..0000000 --- a/hass/settings/custom_components/hacs/http.py +++ /dev/null @@ -1,262 +0,0 @@ -"""Blueprint for HacsWebResponse.""" -import os -from time import time -from homeassistant.components.http import HomeAssistantView -from jinja2 import Environment, PackageLoader -from aiohttp import web - -from integrationhelper import Logger - -from .hacsbase import Hacs - - -WEBRESPONSE = {} - - -def webresponse(classname): - """Decorator used to register Web Responses.""" - WEBRESPONSE[classname.endpoint] = classname - return classname - - -class HacsExperimental(HomeAssistantView, Hacs): - """Base View Class for HACS.""" - - requires_auth = False - name = "hacs" - url = r"/hacs_experimental/{requested_file:.+}" - - def __init__(self): - """Initialize.""" - self.logger = Logger("hacs.http") - - async def get(self, request, requested_file): # pylint: disable=unused-argument - """Handle HACS Experimental Web requests.""" - servefile = f"{self.system.config_path}/custom_components/hacs/frontend/experimental/{requested_file}" - - # Serve .gz file if it exist - if os.path.exists(f"{servefile}.gz"): - servefile += ".gz" - - if os.path.exists(servefile): - return web.FileResponse(servefile) - else: - return web.Response(status=404) - - -class HacsWebResponse(HomeAssistantView, Hacs): - """Base View Class for HACS.""" - - requires_auth = False - name = "hacs" - - def __init__(self): - """Initialize.""" - self.logger = Logger("hacs.http") - self.url = self.hacsweb + "/{path:.+}" - self.endpoint = None - self.postdata = None - self.raw_headers = None - self.repository_id = None - self.request = None - self.requested_file = None - - async def get(self, request, path): # pylint: disable=unused-argument - """Handle HACS Web requests.""" - if self.system.disabled: - return web.Response(status=404) - self.endpoint = path.split("/")[0] - self.raw_headers = request.raw_headers - self.request = request - self.requested_file = path.replace(self.endpoint + "/", "") - self.repository_id = path.replace(self.endpoint + "/", "") - if self.endpoint != "static": - self.logger.debug(f"Endpoint ({self.endpoint}) called") - if self.endpoint in WEBRESPONSE: - try: - response = WEBRESPONSE[self.endpoint] - response = await response.response(self) - except Exception as exception: - render = self.render("error", message=exception) - return web.Response( - body=render, content_type="text/html", charset="utf-8" - ) - else: - # Return default response. - response = await WEBRESPONSE["generic"].response(self) - - # set headers - response.headers["Cache-Control"] = "no-cache, must-revalidate, s-max_age=0" - response.headers["Pragma"] = "no-cache" - - # serve the response - return response - - def render(self, templatefile, location=None, repository=None, message=None): - """Render a template file.""" - loader = Environment(loader=PackageLoader("custom_components.hacs.frontend")) - template = loader.get_template(templatefile + ".html") - return template.render( - { - "hacs": self, - "location": location, - "repository": repository, - "message": message, - "timestamp": time(), - } - ) - - -class HacsPluginView(HacsWebResponse): - """Serve plugins.""" - - name = "hacs:plugin" - - def __init__(self): - """Initialize.""" - self.url = r"/community_plugin/{requested_file:.+}" - - async def get(self, request, requested_file): # pylint: disable=unused-argument - """Serve plugins for lovelace.""" - try: - # Strip '?' from URL - if "?" in requested_file: - requested_file = requested_file.split("?")[0] - - file = f"{self.system.config_path}/www/community/{requested_file}" - - # Serve .gz if it exist - if os.path.exists(file + ".gz"): - file += ".gz" - - response = None - if os.path.exists(file): - self.logger.debug("Serving {} from {}".format(requested_file, file)) - response = web.FileResponse(file) - response.headers["Cache-Control"] = "max-age=0, must-revalidate" - else: - self.logger.error(f"Tried to serve up '{file}' but it does not exist") - response = web.Response(status=404) - - except Exception as error: # pylint: disable=broad-except - self.logger.debug( - "there was an issue trying to serve {} - {}".format( - requested_file, error - ) - ) - response = web.Response(status=404) - - return response - - -class HacsPlugin(HacsPluginView): - """Alias for HacsPluginView.""" - - def __init__(self): - """Initialize.""" - self.url = r"/hacsplugin/{requested_file:.+}" - - -@webresponse -class Settings(HacsWebResponse): - """Serve HacsSettingsView.""" - - endpoint = "settings" - - async def response(self): - """Serve HacsOverviewView.""" - message = self.request.rel_url.query.get("message") - render = self.render("settings", "settings", message=message) - return web.Response(body=render, content_type="text/html", charset="utf-8") - - -@webresponse -class Static(HacsWebResponse): - """Serve static files.""" - - endpoint = "static" - - async def response(self): - """Serve static files.""" - servefile = f"{self.system.config_path}/custom_components/hacs/frontend/elements/{self.requested_file}" - if os.path.exists(servefile + ".gz"): - return web.FileResponse(servefile + ".gz") - else: - if os.path.exists(servefile): - return web.FileResponse(servefile) - else: - return web.Response(status=404) - - -@webresponse -class Store(HacsWebResponse): - """Serve HacsOverviewView.""" - - endpoint = "store" - - async def response(self): - """Serve HacsStoreView.""" - render = self.render("overviews", "store") - return web.Response(body=render, content_type="text/html", charset="utf-8") - - -@webresponse -class Overview(HacsWebResponse): - """Serve HacsOverviewView.""" - - endpoint = "overview" - - async def response(self): - """Serve HacsOverviewView.""" - render = self.render("overviews", "overview") - return web.Response(body=render, content_type="text/html", charset="utf-8") - - -@webresponse -class Repository(HacsWebResponse): - """Serve HacsRepositoryView.""" - - endpoint = "repository" - - async def response(self): - """Serve HacsRepositoryView.""" - message = self.request.rel_url.query.get("message") - repository = self.get_by_id(str(self.repository_id)) - if repository is None: - self.logger.error(f"No repository found with ID {str(self.repository_id)}") - return web.Response(status=404) - - if not repository.status.updated_info: - await repository.update_repository() - repository.status.updated_info = True - - await self.data.async_write() - - if repository.status.new: - repository.status.new = False - await self.data.async_write() - - render = self.render("repository", repository=repository, message=message) - return web.Response(body=render, content_type="text/html", charset="utf-8") - - -@webresponse -class Error(HacsWebResponse): - """Serve error page.""" - - endpoint = "error" - - async def response(self): - """Serve error page.""" - # Generate content - content = """ -
- -
- """ - - return web.Response( - body=self.render("error", message=content), - content_type="text/html", - charset="utf-8", - ) diff --git a/hass/settings/custom_components/hacs/manifest.json b/hass/settings/custom_components/hacs/manifest.json deleted file mode 100644 index 498b779..0000000 --- a/hass/settings/custom_components/hacs/manifest.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "domain": "hacs", - "name": "HACS (Home Assistant Community Store)", - "documentation": "https://hacs.xyz", - "dependencies": [ - "websocket_api", - "frontend", - "persistent_notification" - ], - "config_flow": true, - "codeowners": [ - "@ludeeus" - ], - "homeassistant": "0.98.0", - "requirements": [ - "aiofiles==0.4.0", - "attrs==19.2.0", - "aiogithubapi==0.4.2", - "backoff==1.8.0", - "integrationhelper==0.2.2", - "semantic_version==2.8.2" - ] -} \ No newline at end of file diff --git a/hass/settings/custom_components/hacs/repositories/__init__.py b/hass/settings/custom_components/hacs/repositories/__init__.py deleted file mode 100644 index b4cfae8..0000000 --- a/hass/settings/custom_components/hacs/repositories/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Initialize repositories.""" -from .theme import HacsTheme -from .integration import HacsIntegration -from .python_script import HacsPythonScript -from .appdaemon import HacsAppdaemon -from .plugin import HacsPlugin diff --git a/hass/settings/custom_components/hacs/repositories/appdaemon.py b/hass/settings/custom_components/hacs/repositories/appdaemon.py deleted file mode 100644 index 6e5dba7..0000000 --- a/hass/settings/custom_components/hacs/repositories/appdaemon.py +++ /dev/null @@ -1,87 +0,0 @@ -"""Class for appdaemon apps in HACS.""" -from .repository import HacsRepository, register_repository_class - - -@register_repository_class -class HacsAppdaemon(HacsRepository): - """Appdaemon apps in HACS.""" - - category = "appdaemon" - - def __init__(self, full_name): - """Initialize.""" - super().__init__() - self.information.full_name = full_name - self.information.category = self.category - self.content.path.local = self.localpath - self.content.path.remote = "apps" - - @property - def localpath(self): - """Return localpath.""" - return f"{self.system.config_path}/appdaemon/apps/{self.information.name}" - - async def validate_repository(self): - """Validate.""" - await self.common_validate() - - # Custom step 1: Validate content. - addir = await self.repository_object.get_contents("apps", self.ref) - if not isinstance(addir, list): - self.validate.errors.append("Repostitory structure not compliant") - - self.content.path.remote = addir[0].path - self.information.name = addir[0].name - self.content.objects = await self.repository_object.get_contents( - self.content.path.remote, self.ref - ) - - self.content.files = [] - for filename in self.content.objects: - self.content.files.append(filename.name) - - # Handle potential errors - if self.validate.errors: - for error in self.validate.errors: - if not self.system.status.startup: - self.logger.error(error) - return self.validate.success - - async def registration(self): - """Registration.""" - if not await self.validate_repository(): - return False - - # Run common registration steps. - await self.common_registration() - - # Set local path - self.content.path.local = self.localpath - - async def update_repository(self): - """Update.""" - if self.github.ratelimits.remaining == 0: - return - await self.common_update() - - # Get appdaemon objects. - if self.repository_manifest: - if self.repository_manifest.content_in_root: - self.content.path.remote = "" - - if self.content.path.remote == "apps": - addir = await self.repository_object.get_contents( - self.content.path.remote, self.ref - ) - self.content.path.remote = addir[0].path - self.information.name = addir[0].name - self.content.objects = await self.repository_object.get_contents( - self.content.path.remote, self.ref - ) - - self.content.files = [] - for filename in self.content.objects: - self.content.files.append(filename.name) - - # Set local path - self.content.path.local = self.localpath diff --git a/hass/settings/custom_components/hacs/repositories/integration.py b/hass/settings/custom_components/hacs/repositories/integration.py deleted file mode 100644 index ec56472..0000000 --- a/hass/settings/custom_components/hacs/repositories/integration.py +++ /dev/null @@ -1,164 +0,0 @@ -"""Class for integrations in HACS.""" -import json -from aiogithubapi import AIOGitHubException -from homeassistant.loader import async_get_custom_components -from .repository import HacsRepository, register_repository_class - - -@register_repository_class -class HacsIntegration(HacsRepository): - """Integrations in HACS.""" - - category = "integration" - - def __init__(self, full_name): - """Initialize.""" - super().__init__() - self.information.full_name = full_name - self.information.category = self.category - self.domain = None - self.content.path.remote = "custom_components" - self.content.path.local = self.localpath - - @property - def localpath(self): - """Return localpath.""" - return f"{self.system.config_path}/custom_components/{self.domain}" - - @property - def config_flow(self): - """Return bool if integration has config_flow.""" - if self.manifest: - if self.information.full_name == "hacs/integration": - return False - return self.manifest.get("config_flow", False) - return False - - async def validate_repository(self): - """Validate.""" - await self.common_validate() - - # Attach repository - if self.repository_object is None: - self.repository_object = await self.github.get_repo( - self.information.full_name - ) - - # Custom step 1: Validate content. - if self.repository_manifest: - if self.repository_manifest.content_in_root: - self.content.path.remote = "" - - if self.content.path.remote == "custom_components": - ccdir = await self.repository_object.get_contents( - self.content.path.remote, self.ref - ) - if not isinstance(ccdir, list): - self.validate.errors.append("Repostitory structure not compliant") - - for item in ccdir or []: - if item.type == "dir": - self.content.path.remote = item.path - break - - if self.repository_manifest.zip_release: - self.content.objects = self.releases.last_release_object.assets - - else: - self.content.objects = await self.repository_object.get_contents( - self.content.path.remote, self.ref - ) - - self.content.files = [] - for filename in self.content.objects or []: - self.content.files.append(filename.name) - - if not await self.get_manifest(): - self.validate.errors.append("Missing manifest file.") - - # Handle potential errors - if self.validate.errors: - for error in self.validate.errors: - if not self.system.status.startup: - self.logger.error(error) - return self.validate.success - - async def registration(self): - """Registration.""" - if not await self.validate_repository(): - return False - - # Run common registration steps. - await self.common_registration() - - # Get the content of the manifest file. - await self.get_manifest() - - # Set local path - self.content.path.local = self.localpath - - async def update_repository(self): - """Update.""" - if self.github.ratelimits.remaining == 0: - return - await self.common_update() - - # Get integration objects. - - if self.repository_manifest: - if self.repository_manifest.content_in_root: - self.content.path.remote = "" - - if self.content.path.remote == "custom_components": - ccdir = await self.repository_object.get_contents( - self.content.path.remote, self.ref - ) - if not isinstance(ccdir, list): - self.validate.errors.append("Repostitory structure not compliant") - - self.content.path.remote = ccdir[0].path - - try: - self.content.objects = await self.repository_object.get_contents( - self.content.path.remote, self.ref - ) - except AIOGitHubException: - return - - self.content.files = [] - for filename in self.content.objects or []: - self.content.files.append(filename.name) - - await self.get_manifest() - - # Set local path - self.content.path.local = self.localpath - - async def reload_custom_components(self): - """Reload custom_components (and config flows)in HA.""" - self.logger.info("Reloading custom_component cache") - del self.hass.data["custom_components"] - await async_get_custom_components(self.hass) - - async def get_manifest(self): - """Get info from the manifest file.""" - manifest_path = f"{self.content.path.remote}/manifest.json" - try: - manifest = await self.repository_object.get_contents( - manifest_path, self.ref - ) - manifest = json.loads(manifest.content) - except Exception: # pylint: disable=broad-except - return False - - if manifest: - self.manifest = manifest - self.information.authors = manifest["codeowners"] - self.domain = manifest["domain"] - self.information.name = manifest["name"] - self.information.homeassistant_version = manifest.get("homeassistant") - - # Set local path - self.content.path.local = self.localpath - return True - return False diff --git a/hass/settings/custom_components/hacs/repositories/manifest.py b/hass/settings/custom_components/hacs/repositories/manifest.py deleted file mode 100644 index a3c2084..0000000 --- a/hass/settings/custom_components/hacs/repositories/manifest.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Manifest handling of a repository. - -https://hacs.xyz/docs/publish/start#hacsjson -""" -from typing import List -import attr - -from custom_components.hacs.hacsbase.exceptions import HacsRepositoryInfo - - -@attr.s(auto_attribs=True) -class HacsManifest: - """HacsManifest class.""" - - name: str = None - content_in_root: bool = False - zip_release: bool = False - filename: str = None - manifest: dict = {} - hacs: str = None - domains: List[str] = [] - country: List[str] = [] - homeassistant: str = None - persistent_directory: str = None - iot_class: str = None - render_readme: bool = False - - @staticmethod - def from_dict(manifest: dict): - """Set attributes from dicts.""" - if manifest is None: - raise HacsRepositoryInfo("Missing manifest data") - - manifest_data = HacsManifest() - - manifest_data.manifest = manifest - - for key in manifest: - setattr(manifest_data, key, manifest[key]) - return manifest_data diff --git a/hass/settings/custom_components/hacs/repositories/plugin.py b/hass/settings/custom_components/hacs/repositories/plugin.py deleted file mode 100644 index 5b45a85..0000000 --- a/hass/settings/custom_components/hacs/repositories/plugin.py +++ /dev/null @@ -1,169 +0,0 @@ -"""Class for plugins in HACS.""" -import json -from aiogithubapi import AIOGitHubException -from .repository import HacsRepository, register_repository_class - - -@register_repository_class -class HacsPlugin(HacsRepository): - """Plugins in HACS.""" - - category = "plugin" - - def __init__(self, full_name): - """Initialize.""" - super().__init__() - self.information.full_name = full_name - self.information.category = self.category - self.information.file_name = None - self.information.javascript_type = None - self.content.path.local = ( - f"{self.system.config_path}/www/community/{full_name.split('/')[-1]}" - ) - - async def validate_repository(self): - """Validate.""" - # Run common validation steps. - await self.common_validate() - - # Custom step 1: Validate content. - await self.get_plugin_location() - - if self.content.path.remote is None: - self.validate.errors.append("Repostitory structure not compliant") - - if self.content.path.remote == "release": - self.content.single = True - - self.content.files = [] - for filename in self.content.objects: - self.content.files.append(filename.name) - - # Handle potential errors - if self.validate.errors: - for error in self.validate.errors: - if not self.system.status.startup: - self.logger.error(error) - return self.validate.success - - async def registration(self): - """Registration.""" - if not await self.validate_repository(): - return False - - # Run common registration steps. - await self.common_registration() - - async def update_repository(self): - """Update.""" - if self.github.ratelimits.remaining == 0: - return - # Run common update steps. - await self.common_update() - - # Get plugin objects. - await self.get_plugin_location() - - # Get JS type - await self.parse_readme_for_jstype() - - if self.content.path.remote is None: - self.validate.errors.append("Repostitory structure not compliant") - - if self.content.path.remote == "release": - self.content.single = True - - self.content.files = [] - for filename in self.content.objects: - self.content.files.append(filename.name) - - async def get_plugin_location(self): - """Get plugin location.""" - if self.content.path.remote is not None: - return - - possible_locations = ["dist", "release", ""] - - if self.repository_manifest: - if self.repository_manifest.content_in_root: - possible_locations = [""] - - for location in possible_locations: - if self.content.path.remote is not None: - continue - try: - objects = [] - files = [] - if location != "release": - try: - objects = await self.repository_object.get_contents( - location, self.ref - ) - except AIOGitHubException: - continue - else: - await self.get_releases() - if self.releases.releases: - if self.releases.last_release_object.assets is not None: - objects = self.releases.last_release_object.assets - - for item in objects: - if item.name.endswith(".js"): - files.append(item.name) - - # Handler for plug requirement 3 - valid_filenames = [ - f"{self.information.name.replace('lovelace-', '')}.js", - f"{self.information.name}.js", - f"{self.information.name}.umd.js", - f"{self.information.name}-bundle.js", - ] - - if self.repository_manifest: - if self.repository_manifest.filename: - valid_filenames.append(self.repository_manifest.filename) - - for name in valid_filenames: - if name in files: - # YES! We got it! - self.information.file_name = name - self.content.path.remote = location - self.content.objects = objects - self.content.files = files - break - - except SystemError: - pass - - async def get_package_content(self): - """Get package content.""" - try: - package = await self.repository_object.get_contents("package.json") - package = json.loads(package.content) - - if package: - self.information.authors = package["author"] - except Exception: # pylint: disable=broad-except - pass - - async def parse_readme_for_jstype(self): - """Parse the readme looking for js type.""" - readme = None - readme_files = ["readme", "readme.md"] - root = await self.repository_object.get_contents("") - for file in root: - if file.name.lower() in readme_files: - readme = await self.repository_object.get_contents(file.name) - break - - if readme is None: - return - - readme = readme.content - for line in readme.splitlines(): - if "type: module" in line: - self.information.javascript_type = "module" - break - elif "type: js" in line: - self.information.javascript_type = "js" - break diff --git a/hass/settings/custom_components/hacs/repositories/python_script.py b/hass/settings/custom_components/hacs/repositories/python_script.py deleted file mode 100644 index 5d6af42..0000000 --- a/hass/settings/custom_components/hacs/repositories/python_script.py +++ /dev/null @@ -1,79 +0,0 @@ -"""Class for python_scripts in HACS.""" -from .repository import HacsRepository, register_repository_class - - -@register_repository_class -class HacsPythonScript(HacsRepository): - """python_scripts in HACS.""" - - category = "python_script" - - def __init__(self, full_name): - """Initialize.""" - super().__init__() - self.information.full_name = full_name - self.information.category = self.category - self.content.path.remote = "python_scripts" - self.content.path.local = f"{self.system.config_path}/python_scripts" - self.content.single = True - - async def validate_repository(self): - """Validate.""" - # Run common validation steps. - await self.common_validate() - - # Custom step 1: Validate content. - self.content.objects = await self.repository_object.get_contents( - self.content.path.remote, self.ref - ) - if not isinstance(self.content.objects, list): - self.validate.errors.append("Repostitory structure not compliant") - - self.content.files = [] - for filename in self.content.objects: - self.content.files.append(filename.name) - - # Handle potential errors - if self.validate.errors: - for error in self.validate.errors: - if not self.system.status.startup: - self.logger.error(error) - return self.validate.success - - async def registration(self): - """Registration.""" - if not await self.validate_repository(): - return False - - # Run common registration steps. - await self.common_registration() - - # Set name - self.information.name = self.content.objects[0].name.replace(".py", "") - - async def update_repository(self): # lgtm[py/similar-function] - """Update.""" - if self.github.ratelimits.remaining == 0: - return - # Run common update steps. - await self.common_update() - - # Get python_script objects. - if self.repository_manifest: - if self.repository_manifest.content_in_root: - self.content.path.remote = "" - - self.content.objects = await self.repository_object.get_contents( - self.content.path.remote, self.ref - ) - - self.content.files = [] - for filename in self.content.objects: - self.content.files.append(filename.name) - - # Update name - self.information.name = self.content.objects[0].name.replace(".py", "") - - self.content.files = [] - for filename in self.content.objects: - self.content.files.append(filename.name) diff --git a/hass/settings/custom_components/hacs/repositories/repository.py b/hass/settings/custom_components/hacs/repositories/repository.py deleted file mode 100644 index e62e2e3..0000000 --- a/hass/settings/custom_components/hacs/repositories/repository.py +++ /dev/null @@ -1,697 +0,0 @@ -"""Repository.""" -# pylint: disable=broad-except, bad-continuation, no-member -import pathlib -import json -import os -import tempfile -import zipfile -from integrationhelper import Validate, Logger -from aiogithubapi import AIOGitHubException -from .manifest import HacsManifest -from ..helpers.misc import get_repository_name -from ..hacsbase import Hacs -from ..hacsbase.backup import Backup -from ..handler.download import async_download_file, async_save_file -from ..helpers.misc import version_is_newer_than_version - - -RERPOSITORY_CLASSES = {} - - -def register_repository_class(cls): - """Register class.""" - RERPOSITORY_CLASSES[cls.category] = cls - return cls - - -class RepositoryVersions: - """Versions.""" - - available = None - available_commit = None - installed = None - installed_commit = None - - -class RepositoryStatus: - """Repository status.""" - - hide = False - installed = False - last_updated = None - new = True - selected_tag = None - show_beta = False - track = True - updated_info = False - first_install = True - - -class RepositoryInformation: - """RepositoryInformation.""" - - additional_info = None - authors = [] - category = None - default_branch = None - description = "" - state = None - full_name = None - file_name = None - javascript_type = None - homeassistant_version = None - last_updated = None - uid = None - info = None - name = None - topics = [] - - -class RepositoryReleases: - """RepositoyReleases.""" - - last_release = None - last_release_object = None - published_tags = [] - objects = [] - releases = False - - -class RepositoryPath: - """RepositoryPath.""" - - local = None - remote = None - - -class RepositoryContent: - """RepositoryContent.""" - - path = None - files = [] - objects = [] - single = False - - -class HacsRepository(Hacs): - """HacsRepository.""" - - def __init__(self): - """Set up HacsRepository.""" - - self.content = RepositoryContent() - self.content.path = RepositoryPath() - self.information = RepositoryInformation() - self.repository_object = None - self.status = RepositoryStatus() - self.state = None - self.manifest = {} - self.repository_manifest = HacsManifest.from_dict({}) - self.validate = Validate() - self.releases = RepositoryReleases() - self.versions = RepositoryVersions() - self.pending_restart = False - self.logger = None - - @property - def pending_upgrade(self): - """Return pending upgrade.""" - if self.status.installed: - if self.display_installed_version != self.display_available_version: - return True - - return False - - @property - def ref(self): - """Return the ref.""" - if self.status.selected_tag is not None: - if self.status.selected_tag == self.information.default_branch: - return self.information.default_branch - return "tags/{}".format(self.status.selected_tag) - - if self.releases.releases: - return "tags/{}".format(self.versions.available) - - return self.information.default_branch - - @property - def custom(self): - """Return flag if the repository is custom.""" - if self.information.full_name.split("/")[0] in [ - "custom-components", - "custom-cards", - ]: - return False - if self.information.full_name in self.common.default: - return False - if self.information.full_name == "hacs/integration": - return False - return True - - @property - def can_install(self): - """Return bool if repository can be installed.""" - target = None - if self.information.homeassistant_version is not None: - target = self.information.homeassistant_version - if self.repository_manifest is not None: - if self.repository_manifest.homeassistant is not None: - target = self.repository_manifest.homeassistant - - if target is not None: - if self.releases.releases: - if version_is_newer_than_version(target, self.system.ha_version): - return False - return True - - @property - def display_name(self): - """Return display name.""" - return get_repository_name( - self.repository_manifest, - self.information.name, - self.information.category, - self.manifest, - ) - - @property - def display_status(self): - """Return display_status.""" - if self.status.new: - status = "new" - elif self.pending_restart: - status = "pending-restart" - elif self.pending_upgrade: - status = "pending-upgrade" - elif self.status.installed: - status = "installed" - else: - status = "default" - return status - - @property - def display_status_description(self): - """Return display_status_description.""" - description = { - "default": "Not installed.", - "pending-restart": "Restart pending.", - "pending-upgrade": "Upgrade pending.", - "installed": "No action required.", - "new": "This is a newly added repository.", - } - return description[self.display_status] - - @property - def display_installed_version(self): - """Return display_authors""" - if self.versions.installed is not None: - installed = self.versions.installed - else: - if self.versions.installed_commit is not None: - installed = self.versions.installed_commit - else: - installed = "" - return installed - - @property - def display_available_version(self): - """Return display_authors""" - if self.versions.available is not None: - available = self.versions.available - else: - if self.versions.available_commit is not None: - available = self.versions.available_commit - else: - available = "" - return available - - @property - def display_version_or_commit(self): - """Does the repositoriy use releases or commits?""" - if self.versions.installed is not None: - version_or_commit = "version" - else: - version_or_commit = "commit" - return version_or_commit - - @property - def main_action(self): - """Return the main action.""" - actions = { - "new": "INSTALL", - "default": "INSTALL", - "installed": "REINSTALL", - "pending-restart": "REINSTALL", - "pending-upgrade": "UPGRADE", - } - return actions[self.display_status] - - async def common_validate(self): - """Common validation steps of the repository.""" - # Attach helpers - self.validate.errors = [] - self.logger = Logger( - f"hacs.repository.{self.information.category}.{self.information.full_name}" - ) - - # Step 1: Make sure the repository exist. - self.logger.debug("Checking repository.") - try: - self.repository_object = await self.github.get_repo( - self.information.full_name - ) - except Exception as exception: # Gotta Catch 'Em All - if not self.system.status.startup: - self.logger.error(exception) - self.validate.errors.append("Repository does not exist.") - return - - # Step 2: Make sure the repository is not archived. - if self.repository_object.archived: - self.validate.errors.append("Repository is archived.") - return - - # Step 3: Make sure the repository is not in the blacklist. - if self.information.full_name in self.common.blacklist: - self.validate.errors.append("Repository is in the blacklist.") - return - - # Step 4: default branch - self.information.default_branch = self.repository_object.default_branch - - # Step 5: Get releases. - await self.get_releases() - - # Step 6: Get the content of hacs.json - await self.get_repository_manifest_content() - - # Set repository name - self.information.name = self.information.full_name.split("/")[1] - - async def common_registration(self): - """Common registration steps of the repository.""" - # Attach logger - if self.logger is None: - self.logger = Logger( - f"hacs.repository.{self.information.category}.{self.information.full_name}" - ) - - # Attach repository - if self.repository_object is None: - self.repository_object = await self.github.get_repo( - self.information.full_name - ) - - # Set id - self.information.uid = str(self.repository_object.id) - - # Set topics - self.information.topics = self.repository_object.topics - - # Set description - if self.repository_object.description: - self.information.description = self.repository_object.description - - async def common_update(self): - """Common information update steps of the repository.""" - # Attach logger - if self.logger is None: - self.logger = Logger( - f"hacs.repository.{self.information.category}.{self.information.full_name}" - ) - - # Attach repository - self.repository_object = await self.github.get_repo(self.information.full_name) - - # Update description - if self.repository_object.description: - self.information.description = self.repository_object.description - - # Update default branch - self.information.default_branch = self.repository_object.default_branch - - # Update last available commit - await self.repository_object.set_last_commit() - self.versions.available_commit = self.repository_object.last_commit - - # Update last updaeted - self.information.last_updated = self.repository_object.pushed_at - - # Update topics - self.information.topics = self.repository_object.topics - - # Get the content of hacs.json - await self.get_repository_manifest_content() - - # Update "info.md" - await self.get_info_md_content() - - # Update releases - await self.get_releases() - - async def install(self): - """Common installation steps of the repository.""" - self.validate.errors = [] - persistent_directory = None - - await self.update_repository() - - if self.repository_manifest: - if self.repository_manifest.persistent_directory: - if os.path.exists( - f"{self.content.path.local}/{self.repository_manifest.persistent_directory}" - ): - persistent_directory = Backup( - f"{self.content.path.local}/{self.repository_manifest.persistent_directory}", - tempfile.TemporaryFile() + "/hacs_persistent_directory/", - ) - persistent_directory.create() - - if self.status.installed and not self.content.single: - backup = Backup(self.content.path.local) - backup.create() - - if self.repository_manifest.zip_release: - validate = await self.download_zip(self.validate) - else: - validate = await self.download_content( - self.validate, - self.content.path.remote, - self.content.path.local, - self.ref, - ) - - if validate.errors: - for error in validate.errors: - self.logger.error(error) - if self.status.installed and not self.content.single: - backup.restore() - - if self.status.installed and not self.content.single: - backup.cleanup() - - if persistent_directory is not None: - persistent_directory.restore() - persistent_directory.cleanup() - - if validate.success: - if self.information.full_name not in self.common.installed: - if self.information.full_name == "hacs/integration": - self.common.installed.append(self.information.full_name) - self.status.installed = True - self.versions.installed_commit = self.versions.available_commit - - if self.status.selected_tag is not None: - self.versions.installed = self.status.selected_tag - else: - self.versions.installed = self.versions.available - - if self.information.category == "integration": - if ( - self.config_flow - and self.information.full_name != "hacs/integration" - ): - await self.reload_custom_components() - else: - self.pending_restart = True - - elif self.information.category == "theme": - try: - await self.hass.services.async_call("frontend", "reload_themes", {}) - except Exception: # pylint: disable=broad-except - pass - self.hass.bus.async_fire( - "hacs/repository", - { - "id": 1337, - "action": "install", - "repository": self.information.full_name, - }, - ) - - async def download_zip(self, validate): - """Download ZIP archive from repository release.""" - try: - contents = False - - for release in self.releases.objects: - self.logger.info(f"ref: {self.ref} --- tag: {release.tag_name}") - if release.tag_name == self.ref.split("/")[1]: - contents = release.assets - - if not contents: - return validate - - for content in contents or []: - filecontent = await async_download_file(self.hass, content.download_url) - - if filecontent is None: - validate.errors.append(f"[{content.name}] was not downloaded.") - continue - - result = await async_save_file( - f"{tempfile.gettempdir()}/{self.repository_manifest.filename}", - filecontent, - ) - with zipfile.ZipFile( - f"{tempfile.gettempdir()}/{self.repository_manifest.filename}", "r" - ) as zip_file: - zip_file.extractall(self.content.path.local) - - if result: - self.logger.info(f"download of {content.name} complete") - continue - validate.errors.append(f"[{content.name}] was not downloaded.") - except Exception: - validate.errors.append(f"Download was not complete.") - - return validate - - async def download_content(self, validate, directory_path, local_directory, ref): - """Download the content of a directory.""" - try: - # Get content - if self.content.single: - contents = self.content.objects - else: - contents = await self.repository_object.get_contents( - directory_path, self.ref - ) - - for content in contents: - if content.type == "dir" and ( - self.repository_manifest.content_in_root - or self.content.path.remote != "" - ): - await self.download_content( - validate, content.path, local_directory, ref - ) - continue - if self.information.category == "plugin": - if not content.name.endswith(".js"): - if self.content.path.remote != "dist": - continue - - self.logger.debug(f"Downloading {content.name}") - - filecontent = await async_download_file(self.hass, content.download_url) - - if filecontent is None: - validate.errors.append(f"[{content.name}] was not downloaded.") - continue - - # Save the content of the file. - if self.content.single: - local_directory = self.content.path.local - - else: - _content_path = content.path - if not self.repository_manifest.content_in_root: - _content_path = _content_path.replace( - f"{self.content.path.remote}/", "" - ) - - local_directory = f"{self.content.path.local}/{_content_path}" - local_directory = local_directory.split("/") - del local_directory[-1] - local_directory = "/".join(local_directory) - - # Check local directory - pathlib.Path(local_directory).mkdir(parents=True, exist_ok=True) - - local_file_path = f"{local_directory}/{content.name}" - result = await async_save_file(local_file_path, filecontent) - if result: - self.logger.info(f"download of {content.name} complete") - continue - validate.errors.append(f"[{content.name}] was not downloaded.") - - except Exception: - validate.errors.append(f"Download was not complete.") - return validate - - async def get_repository_manifest_content(self): - """Get the content of the hacs.json file.""" - try: - manifest = await self.repository_object.get_contents("hacs.json", self.ref) - self.repository_manifest = HacsManifest.from_dict( - json.loads(manifest.content) - ) - except (AIOGitHubException, Exception): # Gotta Catch 'Em All - pass - - async def get_info_md_content(self): - """Get the content of info.md""" - from ..handler.template import render_template - - info = None - info_files = ["info", "info.md"] - - if self.repository_manifest is not None: - if self.repository_manifest.render_readme: - info_files = ["readme", "readme.md"] - try: - root = await self.repository_object.get_contents("", self.ref) - for file in root: - if file.name.lower() in info_files: - - info = await self.repository_object.get_rendered_contents( - file.name, self.ref - ) - break - if info is None: - self.information.additional_info = "" - else: - info = info.replace("<", "<") - info = info.replace("", "
").replace("
", "") - info = info.replace("

", "

").replace("
", "") - info = info.replace("

", "

").replace("

", "") - info = info.replace("", "") - info = info.replace( - '", "
  • ") - - # Special changes that needs to be done: - info = info.replace( - "