From 5f4ef3b5b5bf521aaffb4d5ce9e823d600c7698a Mon Sep 17 00:00:00 2001 From: Michael Housh Date: Thu, 12 Dec 2024 19:39:52 -0500 Subject: [PATCH] feat: Moves playbook into resources of cli-client. --- Package.swift | 1 + Sources/CliClient/CliClient+Commands.swift | 13 +- Sources/CliClient/Constants.swift | 1 + .../ansible-hpa-playbook/.editorconfig | 13 + .../Resources/ansible-hpa-playbook/LICENSE | 20 ++ .../Resources/ansible-hpa-playbook/README.md | 1 + .../ansible-hpa-playbook/ansible.cfg | 4 + .../ansible-hpa-playbook/inventory.ini | 3 + .../Resources/ansible-hpa-playbook/justfile | 36 ++ .../Resources/ansible-hpa-playbook/main.yml | 15 + .../roles/build-project/defaults/main.yml | 31 ++ .../roles/build-project/tasks/main.yml | 36 ++ .../roles/load-template-vars/tasks/main.yml | 42 +++ .../prepare-template-facts/tasks/main.yml | 21 ++ .../roles/repo-template/defaults/main.yml | 5 + .../roles/repo-template/files/Definitions.md | 47 +++ .../roles/repo-template/files/Report.md | 307 ++++++++++++++++++ .../roles/repo-template/files/footer.tex | 26 ++ .../roles/repo-template/files/head.tex | 74 +++++ .../repo-template/files/vars.default.yml | 31 ++ .../roles/repo-template/files/vars.repo.yml | 5 + .../roles/repo-template/files/vars.vault.yml | 18 + .../repo-template/files/vault.default.yml | 20 ++ .../roles/repo-template/tasks/main.yml | 46 +++ .../roles/setup-project/defaults/main.yml | 49 +++ .../tasks/copy_if_not_exists.yml | 19 ++ .../roles/setup-project/tasks/main.yml | 120 +++++++ .../roles/setup-project/templates/setup.txt | 7 + .../ansible-hpa-playbook/test/ansible.cfg | 3 + .../ansible-hpa-playbook/test/justfile | 2 + .../ansible-hpa-playbook/test/test.yml | 61 ++++ 31 files changed, 1076 insertions(+), 1 deletion(-) create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/.editorconfig create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/LICENSE create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/README.md create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/ansible.cfg create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/inventory.ini create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/justfile create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/main.yml create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/build-project/defaults/main.yml create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/build-project/tasks/main.yml create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/load-template-vars/tasks/main.yml create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/prepare-template-facts/tasks/main.yml create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/defaults/main.yml create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/Definitions.md create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/Report.md create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/footer.tex create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/head.tex create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vars.default.yml create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vars.repo.yml create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vars.vault.yml create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vault.default.yml create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/tasks/main.yml create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/defaults/main.yml create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/tasks/copy_if_not_exists.yml create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/tasks/main.yml create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/templates/setup.txt create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/test/ansible.cfg create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/test/justfile create mode 100644 Sources/CliClient/Resources/ansible-hpa-playbook/test/test.yml diff --git a/Package.swift b/Package.swift index 9c7b059..401d94d 100644 --- a/Package.swift +++ b/Package.swift @@ -42,6 +42,7 @@ let package = Package( .product(name: "ShellClient", package: "swift-shell-client") ], resources: [ + .copy("Resources/ansible-hpa-playbook"), .copy("Resources/Brewfile") ] ), diff --git a/Sources/CliClient/CliClient+Commands.swift b/Sources/CliClient/CliClient+Commands.swift index b059c2c..89aa131 100644 --- a/Sources/CliClient/CliClient+Commands.swift +++ b/Sources/CliClient/CliClient+Commands.swift @@ -147,10 +147,21 @@ public extension ConfigurationClient { @_spi(Internal) public extension Configuration { + func defaultPlaybookDirectory() throws -> String { + let playbookDirectory = Bundle.module.url( + forResource: Constants.playbookBundleDirectoryName, + withExtension: nil + ) + guard let playbookDirectory else { + throw CliClientError.playbookDirectoryNotFound + } + return playbookDirectory.cleanFilePath + } + func ensuredPlaybookDirectory(_ optionalDirectory: String?) throws -> String { guard let directory = optionalDirectory else { guard let directory = playbook?.directory else { - throw CliClientError.playbookDirectoryNotFound + return try defaultPlaybookDirectory() } return directory } diff --git a/Sources/CliClient/Constants.swift b/Sources/CliClient/Constants.swift index 7e179f9..5525a20 100644 --- a/Sources/CliClient/Constants.swift +++ b/Sources/CliClient/Constants.swift @@ -1,5 +1,6 @@ enum Constants { static let executableName = "hpa" + static let playbookBundleDirectoryName = "ansible-hpa-playbook" static let playbookCommand = "ansible-playbook" static let playbookFileName = "main.yml" static let inventoryFileName = "inventory.ini" diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/.editorconfig b/Sources/CliClient/Resources/ansible-hpa-playbook/.editorconfig new file mode 100644 index 0000000..5d12634 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/.editorconfig @@ -0,0 +1,13 @@ +# editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/LICENSE b/Sources/CliClient/Resources/ansible-hpa-playbook/LICENSE new file mode 100644 index 0000000..debb57b --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2024 Michael Housh + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/README.md b/Sources/CliClient/Resources/ansible-hpa-playbook/README.md new file mode 100644 index 0000000..f4bfab8 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/README.md @@ -0,0 +1 @@ +# ansible-hpa-playbook diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/ansible.cfg b/Sources/CliClient/Resources/ansible-hpa-playbook/ansible.cfg new file mode 100644 index 0000000..9da3d76 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +inventory = ./inventory.ini +roles_path = ./roles +interpreter_python = auto_silent diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/inventory.ini b/Sources/CliClient/Resources/ansible-hpa-playbook/inventory.ini new file mode 100644 index 0000000..34daebd --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/inventory.ini @@ -0,0 +1,3 @@ + +[local] +127.0.0.1 ansible_connection=local diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/justfile b/Sources/CliClient/Resources/ansible-hpa-playbook/justfile new file mode 100644 index 0000000..5ba90ec --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/justfile @@ -0,0 +1,36 @@ +[private] +default: + just --list + +# Run the playbook with the passed in arguments. +[group('plays')] +run *ARGS: + @ansible-playbook ./main.yml \ + --inventory ./inventory.ini \ + {{ARGS}} + +# Run the repo-template option in the `dir` with the passed in arguements. +[group('plays')] +create-repo-template dir *ARGS: + @just run \ + --tags repo-template \ + --extra-vars output_dir={{dir}} \ + {{ARGS}} + +# Run the build-project option in the `dir` with the passed in arguements. +[group('plays')] +build-project dir *ARGS: + @just run \ + --tags build-project \ + --extra-vars project_dir={{dir}} \ + {{ARGS}} + +# Setup a new consult project from a template repo. +[group('plays')] +setup-project repo-url version project-dir *ARGS: + @ansible-playbook ./main.yml \ + --inventory ./inventory.ini \ + --tags setup-project \ + --extra-vars "{'template': {'repo': {'url': '{{repo-url}}', 'version': '{{version}}' }}}" \ + --extra-vars "project_dir={{project-dir}}" \ + {{ARGS}} diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/main.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/main.yml new file mode 100644 index 0000000..dde12ca --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/main.yml @@ -0,0 +1,15 @@ +--- +- name: HPA Playbook + hosts: all + roles: + - role: repo-template + tags: + - repo-template + - never # makes it so a tag must be supplied to run. + - role: build-project + tags: + - build-project + - never # makes it so a tag must be supplied to run. + - role: setup-project + tags: + - never # makes it so a tag must be supplied to run. diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/build-project/defaults/main.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/build-project/defaults/main.yml new file mode 100644 index 0000000..72f1838 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/build-project/defaults/main.yml @@ -0,0 +1,31 @@ +--- +build_dir_name: ".build" +build_dir: "{{ project_dir }}/{{ build_dir_name }}" + +project_dir: "{{ lookup('env', 'PWD') }}" +project_vars_dir: "{{ project_dir }}" + +# template: +# path: "/path/to/template/dir +# vars: "repo_vars" +# repo: (optional if using a repo as a template) +template: + path: "/path/to/template/dir" + vars: "repo_vars" + + # When using a repository as a template dir. In general, it's + # probably best to pin to a particular version of the repo template + # instead of a branch. + # + # repo: + # url: "https://example.com/repo.git" + # version: "main" + repo: {} + +copy_on_build: + - "{{ template.path }}/head.tex" + - "{{ template.path }}/Definitions.md" + +template_on_build: + - "{{ project_dir }}/Report.md" + - "{{ template.path }}/footer.tex" diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/build-project/tasks/main.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/build-project/tasks/main.yml new file mode 100644 index 0000000..222f099 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/build-project/tasks/main.yml @@ -0,0 +1,36 @@ +--- +- name: Starting build project. + ansible.builtin.debug: + msg: "Build dir: {{ build_dir }}" + +- name: Load project vars. + ansible.builtin.include_vars: + dir: "{{ project_vars_dir }}" + ignore_unknown_extensions: true + +- name: Ensure build directory exists. + ansible.builtin.file: + path: "{{ build_dir }}" + state: directory + +- name: Parse template facts. + ansible.builtin.include_role: + name: "prepare-template-facts" + +- name: Load repo vars. + ansible.builtin.include_role: + name: "load-template-vars" + +- name: Copy build files. + ansible.builtin.copy: + src: "{{ item }}" + dest: "{{ build_dir }}/{{ item | basename }}" + mode: '0600' + with_items: "{{ copy_on_build }}" + +- name: Template build files. + ansible.builtin.template: + src: "{{ item }}" + dest: "{{ build_dir }}/{{ item | basename }}" + mode: '0600' + with_items: "{{ template_on_build }}" diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/load-template-vars/tasks/main.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/load-template-vars/tasks/main.yml new file mode 100644 index 0000000..791694c --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/load-template-vars/tasks/main.yml @@ -0,0 +1,42 @@ +--- +# Used internally to clone the template repo, if applicable and load it's +# variables. +# +# NOTE: This expects that you've called prepare-template-facts first. + +- name: Check if template path exists. + ansible.builtin.stat: + path: "{{ template_dir }}" + register: template_dir_stat + tags: + - always + +- name: Debug template variable. + ansible.builtin.debug: + var: template + tags: + - debug + - never + +- name: Ensure repo. + ansible.builtin.git: + repo: "{{ template.repo.url }}" + dest: "{{ template_dir }}" + version: "{{ template.repo.version | default('main') }}" + when: template.repo.url is defined + tags: + - always + +- name: Check for repo vars directory. + ansible.builtin.stat: + path: "{{ template_vars_path }}" + register: repo_vars + tags: + - always + +- name: Load repo vars if available. + ansible.builtin.include_vars: + dir: "{{ template_vars_path }}" + when: repo_vars.stat.isdir is defined + tags: + - always diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/prepare-template-facts/tasks/main.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/prepare-template-facts/tasks/main.yml new file mode 100644 index 0000000..efe7b24 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/prepare-template-facts/tasks/main.yml @@ -0,0 +1,21 @@ +--- +# This role is used internally to parse template variables, depending on +# what is supplied. +# +- name: Set default template path. + ansible.builtin.set_fact: + repo_template_path: "{{ build_dir }}/template" + tags: + - always + +- name: Parse template path. + ansible.builtin.set_fact: + template_dir: "{{ template.path | default(repo_template_path) }}" + tags: + - always + +- name: Parse template vars path. + ansible.builtin.set_fact: + template_vars_path: "{{ template_dir }}/{{ template.vars | default('repo_vars') }}" + tags: + - always diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/defaults/main.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/defaults/main.yml new file mode 100644 index 0000000..0778bd7 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/defaults/main.yml @@ -0,0 +1,5 @@ +--- + +output_dir: "{{ lookup('env', 'PWD') }}" +use_vault: true +repo_vars_dir: "repo_vars" diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/Definitions.md b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/Definitions.md new file mode 100644 index 0000000..32c2160 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/Definitions.md @@ -0,0 +1,47 @@ +# Definitions + + + +### CFM50 {#cfm50-definition} + +Is a unit of measurement that is taken when a blower door test is performed on the home. Stands for +$C$ubic $F$eet per $M$inute at 50 pascals. + +### IAQ {#iaq-definition} + +Stands for $I$ndoor $A$ir $Q$uality. We spend most of our time indoors, so having good indoor air +quality can help reduce illness and potentially improve the quality and longevity of life. + +### LAIR {#lair-definition} + +Stands for $L$eakage $A$ir $I$nfiltration $R$ate, which is a metric that compares the square footage +of the home and it's blower door number. This aids in determining if a home is controllable by +properly sized HVAC equipment or if [shell] improvements (air sealing and insulation) should be +considered. + +### Load Caclulation {#load-calculation-definition} + +A load calculation, also called a Manual-J, calculates the heating and cooling requirements for a +home. Each home has a unique heating and cooling load based on the direction it faces, the air +leakage, the location, the insulation values, the types and sizes of windows, among other factors. + +### Shell {#shell-definition} + +Shell is a term used to describe the enclosure of the house. It is often used when talking about air +leakage and insulation levels. + +### SHR {#shr-definition} + +Stands for $S$ensible $H$eat $R$atio. Sensible heat ratio is the ratio of work required by the air +conditioner to remove moisture, as well as maintain the sensible temperature. The higher the number +the better. + +### TESP {#tesp-definition} + +Stands for $T$otal $E$xternal $S$tatic $P$ressure, which is a metric used to determine how much +resistance the blower motor has to overcome for the airflow requirement of the system. + +### WC {#wc-definition} + +Stands for $W$ater $C$olumn, which is a unit of measurement for pressure. diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/Report.md b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/Report.md new file mode 100644 index 0000000..e96009d --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/Report.md @@ -0,0 +1,307 @@ +--- +title: "{{ document_title }}" +author: "{{ author_name }}" +date: \today{} +mainfont: Avenir Next +documentclass: article +fontsize: 12pt +# NOTE: The applegreen is a custom color defined in resources/head.tex +linkcolor: applegreen +urlcolor: applegreen +abstract: | + **Prepared For:** + + {{ customer.name }} + + {{ customer.address.street }} + {{ customer.address.city }}, {{ customer.address.state }} {{ customer.address.zip }} + + ```{=latex} + \begin{center} + ``` + + \ + \ + \ + + [![logo]({{ links.images.logo }}){ width=30% }]({{ company.website }}) + + ```{=latex} + \end{center} + ``` +--- + + + +# Contents + +1. [Introduction](#home-performance-report) + 1. [Your Goals](#your-goals) +1. [Leakage](#how-leaky-is-your-house) +1. [Observations](#observations) + 1. [HVAC](#hvac-observations) + 1. [Home](#home-observations) +1. [Load Calculations](#load-calculations) + 1. [Your Loads](#your-loads) +1. [Airflow Assessment](#airflow-assessment) + 1. [Your Static Measurements](#your-static-measurements) + 1. [Static Pressure Forecast](#static-measurements-forecast) +1. [Summary](#summary) +1. [Definitions](#definitions) + 1. [CFM50] + 1. [IAQ] + 1. [LAIR] + 1. [Load Calculation][load-calculation] + 1. [Shell][shell] + 1. [SHR] + 1. [TESP] + 1. [WC][wc] + +# Home Performance Report + +Thank you for having us to your home for a home performance assessment. I hope that it was +beneficial. We learned a lot about your home and your goals during the brief visit. So, let’s jump +in to some of the things discovered. + +Below is a summary of your goals, house measurements, and our budget discussion as well as my +observations and some recommendations. As part of the service we ran load calculations that help +determine the right sized HVAC for your home as it stand and with some upgrades. Those are attached +as are bids for replacements. + +Once you read the report you’ll have 3 options: do nothing, pick and choose upgrades, or do more +planning for more difficult goals or complex projects. These options are discussed at the end of the +report as well as our leanings for your home. + +\goalsimage + +## Your goals: + + + + + + +1. Add air conditioning. + +# How Leaky Is Your House + + + +One of the main objectives was to perform a blower door test and load calculations for the home. We +discovered that the blower door number was {{ home.cfm50 }} [CFM50] for the approximately +{{ home.square_feet }} \squarefoot ({{ home.lair }} [LAIR]). A leaky home, most often, is an +uncomfortable and uncontrollable home. + +> _Air leakage tends to have one of the largest impacts on the load of a home._ +> +> - _Around 1:1 homes begin to be more controllable / comfortable_ +> - _your home is {{ home.cfm50 }}:{{ home.square_feet }} \squarefoot for a ratio of +> {{ home.lair }}_ +> - _Leaky homes are very difficult to maintain comfort with HVAC alone._ + +# Observations + +The below sections are observations about the current HVAC system and the home. + +## HVAC Observations + + + +1. Current furnace is sized appropriately based on the load of the home. +1. Current duct system is not sized adequately for the system. + 1. Filter is too small for the system. + 1. Return sizing is not adequate. + 1. Supply sizing is marginal. + 1. Current static pressure is already high. + 1. These problems may become worse when AC is installed. + +## Home Observations + + + +1. The house leakage is high for the size of the home. +1. May be hard to control comfort without [shell] improvements. + +# Load Calculations + +Several [load-calculations][load-calculation] were performed on your home to determine the proper +equipment sizing for this application. Below is a comparison of the +[load-calculations][load-calculation] with the current air leakage and several improved air leakage +targets. + +## Your Loads + + + +| [CFM50] | | Heating Total | Cooling Total | [SHR] | [LAIR] | +| -------------------- | ----------- | ------------- | ------------- | -------- | ------------------- | +| **{{ home.cfm50 }}** | **Current** | **55,102** | **20,726** | **0.79** | **{{ home.lair }}** | +| 2,000 | | 40,320 | 17,279 | 0.85 | 1.5:1 | +| 1,350 | | 35,885 | 16,245 | 0.88 | 1:1 | + +> **Note:** +> +> 1. _The lower the heating and cooling total's the better._ +> 1. _An undersized air conditioner is better than an oversized one._ +> 1. _Supplemental dehumidification may be required for [SHR]'s below 0.83._ + +The above table shows the relationship between air leakage and the amount of heating and cooling +that is required for the home. A tight home is easier to control the comfort levels, offers superior +IAQ levels, and lower utility costs. + + + +The projected cooling size required for your home is around 2-Tons for the current leakage rate, or +1.5-Tons if [shell] improvements were made. + +[Here is a link to your load calculation reports][loads-folder] + +# Airflow Assessment + +While on site, we also measured the total system airflow and static pressure of the system. Static +pressure is equivalent to the blood pressure of your system and gives us a better understanding of +the overall ability for the system to provide the proper amount of airflow, as well as how much it +may struggle to do so. + +Static pressure is the amount of resistance that the blower has to work against in order to move air +through the system. Things that have an effect on the static pressure of the system include, air +filters (size and type), duct sizes, amount of ducts, length of ducts, duct fittings and +transitions, as well as internal system components. Each component of the system has a resistance +associated with it that the blower has to overcome, by taking some key measurements we are able to +determine the [TESP] of the system. While there are several static pressures in the system, when we +talk about static pressure we are generally referring to [TESP]. + +Static pressure ([TESP]) has a range of _low_, _acceptable_, or _high_. While these numbers are +specific to the actual equipment, most manufacturers follow similar standards. For the sake of +simplicity, 0.5" [wc] or under is an _acceptable_ target, 0.8" [wc] is generally the max acceptable +static pressure (although we like to stay well below this if possible), and above 0.8" [wc] is +considered _high_ and should be addressed. _Low_ is generally not common and is rarely problematic, +so it is not focused on much. + + + +\newpage + +## Your Static Measurements + +![True Flow Report][trueflow-image]{ height=50% } + + + +The above image is a snapshot of the static pressures recorded for your system. This shows that the +static pressure of your system is very high (1.114" [wc]). The primary culprits for the high static +pressure are that the filter is undersized for the airflow required and the return duct sizing is +small. + +These measurements were taken in the heating mode because your system does not currently have air +conditioning. Currently the heating airflow is on the low side for what is required for your system +(1200 CFM would be ideal). This should be adjusted if possible during the install to get better +performance and efficiency out of the system, given that some static pressures can be improved +during the project. + +\ +\ + +[Here is a link to the full airflow report.][trueflow-file] + + + +\newpage + +## Static Measurements Forecast + +![True Flow Forecast][trueflow-forecast-image]{ height=50% } + + + +The above image is a snapshot is of a forecast of the static pressures after adding air +conditioning. It should be noted that these measurements are based solely on the airflow required +for cooling mode, not for heating mode (in other words, heating mode is going to be higher because +the airflow requirement is higher). + +This shows that with an upgraded filter we can get the static pressure below the 0.8" [wc] max +target while in cooling mode. + +\ +\ + +[Here is a link to the full forecast report.][trueflow-forecast-file] + +# Summary + +The purpose of the home performance assessment is to help find the overlap between the house needs, +the goals, and the budget to see if there's a viable project. + + + +The house is pretty leaky overall. This is due to the age and construction style of the house. This +may lead to comfort problems or trouble maintaining comfort in all areas of the house. + +Based on the [load calculations][load-calculation], the previously quoted systems are too large for +the current load, so we need to update the proposals to be for 2-Ton systems. This will help with +the fact that the static pressure of the system is already really high. The static pressure for +heating will likely still be above the 0.8" [wc] max threshold. + +An upgraded air filter is going to be required to help alleviate the blower motor. Another return +may be required in the living space to further drop the static pressure, however this could likely +be done in the future if desired. I would estimate that adding another return would be in the +**$800-1,200** range. + +While on site it was mentioned that you would like some of the ducts to be sealed that go to the +second floor. This is something that is not included in our general proposals. I would estimate this +to be an additional **$150-300** and will add options in the updated proposals. + +Since the goal is to add air conditioning, then I would recommend going with a 2-Ton system. If the +system does not maintain then you could look into [shell] improvements and air sealing the home. + +Regards, + +\ +\ +\ + +[Here is a link to all the documents][document-folder] + + + + + +[CFM50]: #cfm50-definition "CFM50" +[IAQ]: #iaq-definition "IAQ" +[LAIR]: #lair-definition "LAIR" +[load-calculation]: #load-calculation-definition "load calculation" +[shell]: #shell-definition "shell" +[SHR]: #shr-definition "SHR" +[wc]: #wc-definition "wc" +[TESP]: #tesp-definition "TESP" + + + + + +[trueflow-image]: "{{ links.images.trueflow }}" + + +[trueflow-forecast-image]: "{{ links.images.trueflow_forecast }}" + + + +[loads-folder]: "{{ links.documents.loads_folder }}" +[trueflow-file]: "{{ links.documents.trueflow_file }}" +[trueflow-forecast-file]: "{{ links.documents.trueflow_forecast_file }}" +[document-folder]: "{{ links.documents.document_folder }}" + diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/footer.tex b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/footer.tex new file mode 100644 index 0000000..1937ab9 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/footer.tex @@ -0,0 +1,26 @@ +% customize the footer +\usepackage{fancyhdr} +\pagestyle{fancy} +% clear all footers +\fancyfoot{} +% clear all headers +\fancyhead{} + +% change font size on footer. +\newcommand{\changefont}{ + \fontsize{8}{10}\selectfont +} +% NOTE: What is displayed in the footer of each page. +\fancyfoot[LE,LO]{ + \href{ {{ company.website }} } + {\changefont\textbf{ + {{ company.url_display_title }} + }} +} +\fancyfoot[RE,RO]{\textbf{ + \changefont{ + Phone: \href{tel:{{ company.phone }} }{ + \color{orange}{{ company.phone }} + } + } +}} diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/head.tex b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/head.tex new file mode 100644 index 0000000..a2f14f6 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/head.tex @@ -0,0 +1,74 @@ +% https://jdhao.github.io/2019/05/30/markdown2pdf_pandoc/#the-top +% These were adapted from the above, which was very helpful in getting this +% functional. + +% change style of quote, see also https://tex.stackexchange.com/a/436253/114857 +\usepackage[most]{tcolorbox} + +% change page margins +\usepackage[top=2cm, bottom=1.5cm, left=2cm, right=2cm]{geometry} + +% change the line spacing +\usepackage{setspace} +\setstretch{1.25} + +\usepackage[utf8]{inputenc} + +% NOTE: This needs to stay above hyperref otherwise internal links break. + +% start each section on new page and make section titles orange. +\usepackage{titlesec} +\titleformat{\section} +{\color{orange}\normalfont\Huge\bfseries} +\newcommand{\sectionbreak}{\clearpage} + +% custom colors +\definecolor{applegreen}{rgb}{0.55,0.71,0.0} + +% Remove figure from images +\usepackage[labelformat=empty]{caption} + +\usepackage{fancyvrb,newverbs} + +% see for different color codes https://rgbcolorcode.com/color/E6FFEA +\definecolor{linequote}{RGB}{224,215,188} +\definecolor{backquote}{RGB}{230,255,234} % background color of quotes +\definecolor{bordercolor}{RGB}{221,221,221} + +% change left border: https://tex.stackexchange.com/a/475716/114857 +% change left margin: https://tex.stackexchange.com/a/457936/114857 +\newtcolorbox{myquote}[1][]{% + enhanced, + breakable, + size=minimal, + left=10pt, + top=5pt, + bottom=5pt, + frame hidden, + boxrule=0pt, + sharp corners=all, + colback=backquote, + borderline west={4pt}{0pt}{bordercolor}, + #1 +} + +% redefine quote environment to use the myquote environment, see https://tex.stackexchange.com/a/337587/114857 +\renewenvironment{quote}{\begin{myquote}}{\end{myquote}} + +% remove the abstract title. +\usepackage{abstract} +\renewcommand{\abstractname}{} +\renewcommand{\absnamepos}{empty} + +\def\squarefoot{$ft^{\text{2}}$ } +\def\goalsimage{ +\begin{center} + +\hfill\break +\hfill\break + +\includegraphics[width=0.6\linewidth,height=\textheight,keepaspectratio]{img/goals.png} + +\end{center} + +} diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vars.default.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vars.default.yml new file mode 100644 index 0000000..8a09dc7 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vars.default.yml @@ -0,0 +1,31 @@ +--- +author_name: "Testy McTestface Jr" +document_title: "Home Performance Report" +company: + website: "https://example.com" + phone: "555-555-5555" + url_display_title: "www.Example.com" + +links: + images: + logo: "img/logo.png" + trueflow: "img/trueflow.png" + trueflow_forecast: "img/forecast.png" + documents: + loads_folder: "https://example.com/path/to/loads/folder" + trueflow_file: "https://example.com/path/to/trueflow/file" + trueflow_forecast_file: "https://example.com/path/to/trueflow/forecast/file" + document_folder: "https://example.com/path/to/document/folder" + +customer: + name: "Testy McTestface Sr" + address: + street: "1234 Seasme Street" + city: "No Mans Land" + state: "Foo" + zip: "55555" + +home: + square_feet: "3,000" + cfm50: "3,000" + lair: "1:1" diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vars.repo.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vars.repo.yml new file mode 100644 index 0000000..9370511 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vars.repo.yml @@ -0,0 +1,5 @@ +--- +on_setup: + - "Report.md" + - "vars.yml" + - "vault.yml" # optional if using vault. diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vars.vault.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vars.vault.yml new file mode 100644 index 0000000..7cabc46 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vars.vault.yml @@ -0,0 +1,18 @@ +--- +author_name: "{{ vault_author_name }}" +document_title: "Home Performance Report" +company: "{{ vault_company }}" + +links: + images: + logo: "img/logo.png" + trueflow: "img/trueflow.png" + trueflow_forecast: "img/forecast.png" + documents: "{{ vault_document_links }}" + +customer: "{{ vault_customer }}" + +home: + square_feet: "3,000" + cfm50: "3,000" + lair: "1:1" diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vault.default.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vault.default.yml new file mode 100644 index 0000000..1e94dcb --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/files/vault.default.yml @@ -0,0 +1,20 @@ +--- +vault_author_name: "Testy McTestface Vault" +vault_company: + website: "https://vault.example.com" + phone: "555-555-5555" + url_display_title: "www.VaultExample.com" + +vault_customer: + name: "Testy McTestface Sr Vault" + address: + street: "1234 Seasme Street" + city: "Vault" + state: "Foo" + zip: "55555" + +vault_document_links: + loads_folder: "https://vault.example.com/path/to/loads/folder" + trueflow_file: "https://vault.example.com/path/to/trueflow/file" + trueflow_forecast_file: "https://vault.example.com/path/to/trueflow/forecast/file" + document_folder: "https://vault.example.com/path/to/document/folder" diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/tasks/main.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/tasks/main.yml new file mode 100644 index 0000000..347662f --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/repo-template/tasks/main.yml @@ -0,0 +1,46 @@ +--- +- name: Starting repo template role. + ansible.builtin.debug: + msg: "Output directory: {{ output_dir }}" + +- name: Ensure output directory exists. + ansible.builtin.file: + path: "{{ output_dir }}" + state: directory + +- name: Ensure repo vars directory. + ansible.builtin.file: + path: "{{ output_dir }}/{{ repo_vars_dir }}" + state: directory + +- name: Copy general files. + ansible.builtin.copy: + src: "files/{{ item.src | default(item) }}" + dest: "{{ output_dir }}/{{ item.dest | default(item) }}" + with_items: + - "Definitions.md" + - "Report.md" + - "head.tex" + - "footer.tex" + - src: "vars.repo.yml" + dest: "{{ repo_vars_dir }}/vars.yml" + +- name: Copy basic vars files. + ansible.builtin.copy: + src: "files/vars.default.yml" + dest: "{{ output_dir }}/vars.yml" + when: not 'with-vault' in ansible_run_tags or use_vault | bool == False + +- name: Copy vault and vars files. + ansible.builtin.copy: + src: "files/{{ item.src }}" + dest: "{{ output_dir }}/{{ item.dest }}" + with_items: + - src: "vars.vault.yml" + dest: "vars.yml" + - src: "vault.default.yml" + dest: "vault.yml" + when: "'with_vault' in ansible_run_tags or use_vault | bool == True" + tags: + - with-vault + - never diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/defaults/main.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/defaults/main.yml new file mode 100644 index 0000000..b040a27 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/defaults/main.yml @@ -0,0 +1,49 @@ +--- +# template: +# path: "/path/to/local/template/dir +# vars: "repo_vars" (optional path inside template directory to find variables, defaults to 'repo_vars') +# +# OR +# +# template: +# repo: +# url: "https://example.com/template.git +# version: "1.0.0" or "branch" (tagging to a version is more ideal) +# +template: + +# The preject directory to setup in. +project_dir: "{{ lookup('env', 'PWD') }}" + +# This path get's setup / parsed based on the template variable, +# it will point to the directory of the template, which could be a +# local path on the system or inside of the project directory, depending +# on if the template is a repo or not. +# +# This is safe to use inside of the project or template specifications +# for paths to files that live in the template directory not the project +# directory. +#template_dir: "" + +# Files or directories that are copied from the template directory to the project +# directory. +# +# These can be a simple item that is a path from the root of the template directory +# to a file, which will copy the file to the root of the project directory or +# in the form of: +# +# src: "path/in/template/dir" +# dest: "path/in/project/dir" +# mode: '0600' (optional mode of the file/dir to copy) +# +copy_on_setup: [] + +# Copies the entire contents of a directory to the root of the project directory. +# +# This is useful if you keep all the template files in a sub-directory of your project +# template, it will copy that entire directory over when setting up a new project. +# +# NOTE: If the project has been setup (indicated by a .setup file) this +# will be skipped so that it does not overwrite any changes to the +# project files. This ensures that a project is only setup once. +copy_directory_on_setup: [] diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/tasks/copy_if_not_exists.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/tasks/copy_if_not_exists.yml new file mode 100644 index 0000000..bbf29c3 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/tasks/copy_if_not_exists.yml @@ -0,0 +1,19 @@ +--- +# NOTE: This is just an internal task that checks if a file exists +# before copying, to prevent changes from being overwritten. +# +- name: "Check if {{ destination | basename }} exists already." + ansible.builtin.stat: + path: "{{ destination }}" + register: filestat + tags: + - always + +- name: "Copy {{ destination | basename }} file." + ansible.builtin.copy: + src: "{{ source }}" + dest: "{{ destination }}" + mode: "{{ mode | default('0600') }}" + when: not filestat.stat.exists + tags: + - always diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/tasks/main.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/tasks/main.yml new file mode 100644 index 0000000..ece5dc0 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/tasks/main.yml @@ -0,0 +1,120 @@ +--- +- name: Starting setup project. + ansible.builtin.debug: + msg: "Project dir: {{ project_dir }}" + tags: + - setup-project + - never + +- name: Debug template vars pre parse. + ansible.builtin.debug: + var: template + tags: + - debug + - never + +- name: Debug build dir. + ansible.builtin.debug: + var: build_dir + tags: + - debug + - never + +- name: Parse template facts. + ansible.builtin.include_role: + name: "prepare-template-facts" + tags: + - setup-project + - never + + +- name: Debug template path post parse. + ansible.builtin.debug: + var: template_dir + tags: + - debug + - never + +- name: Ensure output directory exists. + ansible.builtin.file: + path: "{{ project_dir }}" + state: directory + tags: + - setup-project + - never + +- name: Load template vars. + ansible.builtin.include_role: + name: "load-template-vars" + tags: + - setup-project + - never + +- name: Debug on_setup. + ansible.builtin.debug: + msg: "On setup vars: {{ copy_on_setup }}" + tags: + - debug + - never + +- name: Debug copy directory contents. + ansible.builtin.debug: + var: copy_directory_on_setup + tags: + - debug + - never + +- name: Check if project has been previously setup. + ansible.builtin.stat: + path: "{{ project_dir }}/.setup" + register: setup_file + tags: + - setup-project + - never + +- name: Debug setup file stat. + ansible.builtin.debug: + var: setup_file.exists + tags: + - debug + - never + +- name: Copy directory contents to project directory. + ansible.builtin.command: | + cp -r "{{ template_dir }}/{{ item.src | default(item) }}/." \ + "{{ item.dest | default(project_dir) }}" + with_items: "{{ copy_directory_on_setup }}" + when: setup_file.stat.exists is false + register: copy_directory_stat + tags: + - setup-project + - never + +- name: Debug copy directory stat. + ansible.builtin.debug: + var: copy_directory_stat + tags: + - debug + - never + +- name: Copy project files. + ansible.builtin.include_tasks: + file: "copy_if_not_exists.yml" + vars: + source: "{{ template_dir }}/{{ item.src | default(item) }}" + destination: "{{ project_dir }}/{{ item.dest | default(item) }}" + mode: "{{ item.mode | default('0600') }}" + loop: "{{ copy_on_setup }}" + tags: + - setup-project + - never + +- name: Create setup file. + ansible.builtin.template: + src: "templates/setup.txt" + dest: "{{ project_dir }}/.setup" + mode: '0600' + when: not setup_file.stat.exists + tags: + - setup-project + - never diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/templates/setup.txt b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/templates/setup.txt new file mode 100644 index 0000000..75ce69f --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/roles/setup-project/templates/setup.txt @@ -0,0 +1,7 @@ +This file is managed by the ansible-hpa-playbook. It is an indication +that the project using the template. + +{{ template.repo.url | default(template_dir) }} + +Has already called setup. This file should not be removed or subsequent calls +to setup may overwrite existing data. diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/test/ansible.cfg b/Sources/CliClient/Resources/ansible-hpa-playbook/test/ansible.cfg new file mode 100644 index 0000000..979ed4f --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/test/ansible.cfg @@ -0,0 +1,3 @@ +[defaults] +inventory = ../inventory.ini +roles_path = ../roles diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/test/justfile b/Sources/CliClient/Resources/ansible-hpa-playbook/test/justfile new file mode 100644 index 0000000..3bd54d8 --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/test/justfile @@ -0,0 +1,2 @@ +test *ARGS: + @ansible-playbook ./test.yml {{ARGS}} diff --git a/Sources/CliClient/Resources/ansible-hpa-playbook/test/test.yml b/Sources/CliClient/Resources/ansible-hpa-playbook/test/test.yml new file mode 100644 index 0000000..b02788f --- /dev/null +++ b/Sources/CliClient/Resources/ansible-hpa-playbook/test/test.yml @@ -0,0 +1,61 @@ +--- +- name: Test ansible-hpa-playbook + hosts: all + roles: + - role: setup-project + tags: + - setup-project + - never # force passing tags to run. + vars: + template_dir: + path: "/tmp/hpa-playbook-tmp" + vars: "repo_vars" + project_dir: "/tmp/hpa-setup-project-tmp" + + - role: repo-template + tags: + - repo-template + - never # force passing tags to run. + - role: build-project + tags: + - build-project + - never # force passing tags to run. + vars: + template_dir: + path: "/tmp/hpa-playbook-tmp" + vars: "repo_vars" + project_dir: "/tmp/hpa-setup-project-tmp" + + tasks: + - name: Test complex var, set fact. + ansible.builtin.set_fact: + template: + path: "{{ template.path | default('.build') }}" + vars: + template: + repo: + url: "https://example.com" + version: "main" + tags: + - vars + - never + + - name: Test complex var, set fact when path is specified. + ansible.builtin.set_fact: + template_path_specified: true + vars: + template: + repo: + url: "https://example.com" + version: "main" + when: template.path is defined + tags: + - vars + - never + + - name: Test complex var was set. + ansible.builtin.debug: + msg: "Template path: {{ template.path }}, specified: {{ template_path_specified | default(false) }}" + tags: + - vars + - never