Wie ich ein schickes Aquarium gemacht habe (Frontend)

Prolog





Wie ich hier erwähnte , begann ich mit dem Bau eines intelligenten Aquariums, das auf dem Brett basiert NodeMCU. Darauf habe ich die Firmware von verwendet micropython, einen Webserver eingerichtet und eine API erstellt, um alle Peripheriegeräte und Sensoren zu manipulieren. Da meine Version des intelligenten Aquariums ursprünglich als eigenständige Version geplant war, wollte ich eine erstellen, um UIalle Prozesse zu verfolgen und manuelle Anpassungen vorzunehmen. Verwenden Sie jedes Mal Routen des Typs: http://192.168.1.70/led_controller?impulse=4000&level=200&ledName=whiteEs war sehr trostlos und unpraktisch. Besonders wenn Sie bereits ins Bett gegangen sind und nur Ihr Telefon zur Hand ist. Und wieder wollte ich mich weiterentwickeln und etwas Spaß machen.



UI Vue.js. , .. " " WI-FI . , . , , . , , SPA(" ": "single page application"), , . backend — LED- . , vue-cli:



$ vue ui
  Starting GUI...
  Ready on http://localhost:8000




, :



  • vue-bootstrap — .
  • axiosbackend API.
  • vuex


axios url



plugin/axios.js



import Vue from 'vue';
import axios from 'axios';
import VueAxios from 'vue-axios';

axios.defaults.baseURL = 'http://192.168.1.70';

Vue.use(VueAxios, axios);


— , , , . .





App.vue



<template>
  <div id="app">
    <b-navbar type="dark" variant="primary" class="rounded">
      <b-navbar-brand tag="h1" class="mb-0">Fish Tank</b-navbar-brand>
      <b-icon 
        icon="brightness-alt-high" 
        font-scale="3" 
        variant="light" 
        class="rounded bg-primary p-1"
      />
    </b-navbar>
    <list-of-range-controllers/>
  </div>
</template>

<script>
import ListOfRangeControllers from './components/ListOfRangeControllers';

export default {
    name: 'App',
    components: {
        ListOfRangeControllers
    }
}
</script>

<style scoped>
  #app {
      margin: 50px 20px;
  }
</style>


Dann überlegte ich, wie ich die Geschäftslogik selbst organisieren und von der Vorlage trennen sollte. Ich beschloss, es komplett durch die VuexVyuks selbst zu versuchen, nicht geteilt, sondern alles in einer Datei. Für den LED-Pegel verwende ich die From-Skala 0 - 100 %, während der backendLichtpegel selbst aus 0 - 1024Einheiten eingestellt wird. Nach dem Aufrunden dachte ich, ich würde einfach mit 10 multiplizieren, wenn die Daten von der POST Anfrage gesendet werden , oder durch 10 dividieren, wenn die Daten von der GET Anfrage empfangen werden .



store/index.js



import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        whiteLED         : 0,
        waterTemperature : 0,
    },

    mutations: {
        'SYNC_WHITE_LED' (state, level) {
            state.whiteLED = level;
        },
        'SYNC_WATER_TEMPERATURE' (state, level) {
            state.waterTemperature = level;
        },
        'SET_WHITE_LED' (state, level) {
            state.whiteLED = level;
        },
        'SET_HEATER_LEVEL' (state, level) {
            state.waterTemperature = level;
        }
    },

    actions: {
        async syncWhiteLED({commit}) {
            try {
                const response = await Vue.axios.get('/get_led_info?ledName=white');
                commit('SYNC_WHITE_LED', response.data['level']/10);
            }
            catch(error) {
                console.error(error);
            }
        },
        async syncWaterTemperature({commit}) {
            try {
                const response = await Vue.axios.get('/get_water_tmp');
                commit('SYNC_WATER_TEMPERATURE', response.data['water_temperature_c']);
            }
            catch(error) {
                console.error(error);
            }
        },
        async setWhiteLED({commit}, level) {
            try {
                await Vue.axios.get(`/led_controller?impulse=4000&level=${level*10}&ledName=white`);
                commit('SET_WHITE_LED', level);
            }
            catch(error) {
                console.error(error);
            }
        },
        async setWaterTemperature({commit}, level) {
            try {
                await Vue.axios.get(`/heater_control?params=${level}`);
                commit('SET_HEATER_LEVEL', level);
            }
            catch(error) {
                console.error(error);
            }
        },
    },

    getters: {
        whiteLED: state => {
            return state.whiteLED;
        },
        waterTemperature: state => {
          return state.waterTemperature;
        },
    }
})




Als nächstes erstelle ich eine universelle Komponente, in der der aktuelle Wert angezeigt wird, eine Skala zum Ändern des Werts und einige Schaltflächen zum Synchronisieren und tatsächlichen Ändern.

components/ui/RangeController.vue



<template>
    <b-card 
        :title="header" 
    >
        <b-alert show>
            Change to : {{ controllerValue }} 
                        {{
                            name.match(/Water/gi) 
                            ? 'C\u00B0' : '%'
                        }}
        </b-alert>
        <b-form-input 
            type="range"
            :min="min"
            :max="max"
            v-model="controllerValue"
        />
        <b-button 
            variant="outline-primary" 
            size="sm"
            @click="$emit(`${buttonChangeName}Change`, controllerValue)"
        >
            {{ changeButton }}
        </b-button>
        <b-button 
            class="float-right"
            variant="outline-success" 
            size="sm"
            @click="$emit(`${buttonChangeName}Sync`)"
        >
            Sync value
        </b-button>
    </b-card>
</template>

<script>
export default {
    props: {
        name: {
            type    : String,
            default : 'Header',
        },
        value: {
            type    : Number,
            default : 0,
        },
        buttonChangeName: {
            type    : String,
            default : 'Change'
        },
        min: {
            type    : Number,
            default : 0
        },
        max: {
            type    : Number,
            default : 100
        }
    },
    data() {
        return {
            controllerValue: this.min,
        }
    },
    computed: {
        header() {
            const isWater = this.name.match(/Water/gi);
            const postfix = isWater ? 'C\u00B0' : '%';

            const sufix = isWater ? 'Temperature' : this.name.match(/Pump/gi)? '' : 'LED';

            return `${this.name} ${sufix} is : ${this.value} ${postfix}`;
        },
        changeButton() {
            return `${this.buttonChangeName} change`;
        },
    }
}
</script>


, , , - DRY, , , .



components/ListOfRangeControllers.vue



<template>
    <b-container class="bv-example-row mt-4 mb-4">
      <h1>Backlight</h1>
      <b-row>
        <b-col v-for="led in leds" :key="led.name">
          <range-controller
            :name="led.name"
            :value="led.value"
            :buttonChangeName="led.buttonName"
            v-on="{ 
              ledWhiteChange : ledWhiteChange,
              ledWhiteSync   : ledWhiteSync,
            }"
          />
        </b-col>

      </b-row>
      <h1>Temperature</h1>
      <b-row>
        <b-col>
          <range-controller
              name="Water"
              :value="waterTemperature"
              :min="20"
              :max="45"
              buttonChangeName="temperature"
              @temperatureChange="temperatureChange"
              @temperatureSync="temperatureSync"
          />
        </b-col>
      </b-row>

    </b-container>
</template>

<script>
import RangeController from './ui/RangeController';
import { mapActions, mapGetters } from 'vuex'

export default {
    components: {
        RangeController
    },

    methods: {
        ...mapActions([
            'syncWhiteLED',
            'syncWaterTemperature',
            'setWhiteLED',
        ]),

        ledWhiteChange(value) {
            this.setWhiteLED(value);
        },

        //  
        temperatureChange(value) {
            console.log('temp is changed!' + `${value}`);
        },

        ledWhiteSync() {
            this.syncWhiteLED();
        },
        async temperatureSync() {
            await this.syncWaterTemperature();

            console.log(this.waterTemperature);
        },
    },

    computed: {
        ...mapGetters([
            'waterTemperature',
            'whiteLED',
        ]),

        leds() {
            return [
                {
                    name: 'White',
                    value: this.$store.getters.whiteLED,
                    buttonName: 'ledWhite',
                },
            ]
        },
    },
}
</script>










UI , , . , . Vue , … , , , . NodeMCU Vue . . , , . , . . , , :



  • - (Ph)
  • (kH)


- , , . ? . — . NodeMCU "", .






All Articles