From d56cf43a1ad68deaec38f0269f4dc63dbb5834f4 Mon Sep 17 00:00:00 2001 From: Laica-Lunasys Date: Wed, 18 Dec 2019 23:43:47 +0900 Subject: [PATCH 1/4] [WIP] Add error handling --- frontend/src/actions/remote/index.jsx | 22 +++++++++++++++--- frontend/src/components/remote/RemoteCard.jsx | 19 +++++++++++---- frontend/src/reducers/remote/index.jsx | 23 +++++++++++++++---- 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/frontend/src/actions/remote/index.jsx b/frontend/src/actions/remote/index.jsx index 67fa053..04a758f 100644 --- a/frontend/src/actions/remote/index.jsx +++ b/frontend/src/actions/remote/index.jsx @@ -8,13 +8,20 @@ export function fetchRemoteSuccess(payload) { } } +export function fetchRemoteError(error) { + return { + type: 'FETCH_REMOTE_FAILED', + payload: {error}, + } +} + export function fetchRemote(dispatch) { const request = httpClient({ method: 'GET', url: `${API_URL}/api/v1/remote`, }) .then(response => dispatch(fetchRemoteSuccess(response.data))) - .catch(error => error.response); + .catch(error => dispatch(fetchRemoteError(error.response))); return { type: 'FETCH_REMOTE', payload: request @@ -30,7 +37,7 @@ export function fetchRemoteByMode(dispatch, mode) { } }) .then(response => dispatch(fetchRemoteSuccess(response.data))) - .catch(error => error.response); + .catch(error => dispatch(fetchRemoteError(error.response))); return { type: 'FETCH_REMOTE', payload: request @@ -52,6 +59,14 @@ export function postRemoteSuccess(payload) { } } +export function postRemoteError(error) { + console.log('failed') + return { + type: 'POST_REMOTE_FAILED', + error: error, + } +} + export function postRemote(dispatch, payload) { console.log('payload') console.log(payload) @@ -62,7 +77,8 @@ export function postRemote(dispatch, payload) { data: payload, }) .then(response => dispatch(postRemoteSuccess(response.data))) - .catch(error => error.response); + .catch(error => dispatch(postRemoteError(error.response)) + ); return { type: 'POST_REMOTE', payload: request diff --git a/frontend/src/components/remote/RemoteCard.jsx b/frontend/src/components/remote/RemoteCard.jsx index 5cd370a..b544743 100644 --- a/frontend/src/components/remote/RemoteCard.jsx +++ b/frontend/src/components/remote/RemoteCard.jsx @@ -20,8 +20,14 @@ import Toggle from './Toggle'; const mapStateToProps = state => { return { - remote: state.remote.payload, - remoteState: state.remoteState.payload, + remote: { + data: state.remote.payload, + error: state.remote.error + }, + remoteState: { + data: state.remoteState.payload, + error: state.remoteState.error + }, template: state.template.payload } }; @@ -56,7 +62,7 @@ class RemoteCard extends React.Component { // Convert RemoteData to State dataToState(entry) { - let state = {...this.props.remoteState}; + let state = {...this.props.remoteState.data}; // Must be deep-copy children nodes state = { @@ -78,7 +84,7 @@ class RemoteCard extends React.Component { // Convert State to Remote stateToData(m) { // m: mode - const remoteState = {...this.props.remoteState}; + const remoteState = {...this.props.remoteState.data}; const operation = remoteState['operation']; const mode = m ? m : remoteState['mode']; return { @@ -90,7 +96,7 @@ class RemoteCard extends React.Component { render() { //const remote = {...this.state.remote}; - if (!this.props.remoteState || !this.props.template) { + if (!this.props.remoteState.data || !this.props.template) { return (
@@ -105,6 +111,9 @@ class RemoteCard extends React.Component { const remote = this.stateToData(); + console.log(this.props.remote.error) + console.log(this.props.remoteState.error) + return (
diff --git a/frontend/src/reducers/remote/index.jsx b/frontend/src/reducers/remote/index.jsx index 1bc488a..b0b703f 100644 --- a/frontend/src/reducers/remote/index.jsx +++ b/frontend/src/reducers/remote/index.jsx @@ -6,26 +6,41 @@ export const remote = (state = initialState, action) => { case 'FETCH_REMOTE': return { ...state, - payload: null + payload: null, + error: null } case 'FETCH_REMOTE_SUCCESS': return { ...state, - payload: action.payload + payload: action.payload, + error: null + } + case 'FETCH_REMOTE_FAILED': + return { + ...state, + error: action.error } case 'SAVE_REMOTE': return { ...state, - payload: action.payload + payload: action.payload, + error: null } case 'POST_REMOTE': return { ...state, + error: null } case 'POST_REMOTE_SUCCESS': return { ...state, - payload: action.payload + payload: action.payload, + error: null + } + case 'POST_REMOTE_FAILED': + return { + ...state, + error: action.error } default: return state From 46aad78aa5a63223db278644ce4ce8cce227fd46 Mon Sep 17 00:00:00 2001 From: Laica Lunasys Date: Sun, 2 Feb 2020 18:07:30 +0900 Subject: [PATCH 2/4] Improve Error Handling --- frontend/src/actions/remote/index.jsx | 2 +- frontend/src/actions/template/index.jsx | 9 +- frontend/src/components/basement/Modal.jsx | 38 +++ frontend/src/components/remote/RemoteCard.jsx | 302 +++++++++--------- frontend/src/reducers/template/index.jsx | 8 +- 5 files changed, 213 insertions(+), 146 deletions(-) create mode 100644 frontend/src/components/basement/Modal.jsx diff --git a/frontend/src/actions/remote/index.jsx b/frontend/src/actions/remote/index.jsx index 04a758f..9610ec6 100644 --- a/frontend/src/actions/remote/index.jsx +++ b/frontend/src/actions/remote/index.jsx @@ -11,7 +11,7 @@ export function fetchRemoteSuccess(payload) { export function fetchRemoteError(error) { return { type: 'FETCH_REMOTE_FAILED', - payload: {error}, + error: error, } } diff --git a/frontend/src/actions/template/index.jsx b/frontend/src/actions/template/index.jsx index 0266466..a5776a6 100644 --- a/frontend/src/actions/template/index.jsx +++ b/frontend/src/actions/template/index.jsx @@ -8,12 +8,19 @@ export function fetchTemplateSuccess(payload) { } } +export function fetchTemplateError(error) { + return { + type: 'FETCH_TEMPLATE_FAILED', + error: error, + } +} + export function fetchTemplate(dispatch) { const request = httpClient({ method: 'GET', url: `${API_URL}/api/v1/template` }).then(response => dispatch(fetchTemplateSuccess(response.data)) - ).catch(error => error.response); + ).catch(error => dispatch(fetchTemplateError(error.response))); return { type: 'FETCH_TEMPLATE', payload: request diff --git a/frontend/src/components/basement/Modal.jsx b/frontend/src/components/basement/Modal.jsx new file mode 100644 index 0000000..511da18 --- /dev/null +++ b/frontend/src/components/basement/Modal.jsx @@ -0,0 +1,38 @@ +import { Button, Modal } from 'react-bootstrap'; +import React from 'react'; + +class ModalPopup extends React.Component { + constructor(props) { + super(props); + this.state = { + show: true + }; + } + render() { + const { title, body } = this.props; + const handleClose = () => { + this.setState({ + show: false + }) + } + return ( +
+ + + {title} + + {this.props.body} + {this.props.type === "ERROR_MODAL" && + + + + } + +
+ ) + } +} + +export default ModalPopup; diff --git a/frontend/src/components/remote/RemoteCard.jsx b/frontend/src/components/remote/RemoteCard.jsx index b544743..5270efe 100644 --- a/frontend/src/components/remote/RemoteCard.jsx +++ b/frontend/src/components/remote/RemoteCard.jsx @@ -1,4 +1,4 @@ -import { Button, Navbar, Row, Spinner } from 'react-bootstrap'; +import { Button, Navbar, Row, Toast } from 'react-bootstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { connect } from 'react-redux'; import { fas } from '@fortawesome/free-solid-svg-icons'; @@ -7,12 +7,12 @@ import React from 'react'; import styled from 'styled-components'; import { - fetchRemote, - fetchRemoteByMode, - postRemote + fetchRemote, + fetchRemoteByMode, + postRemote } from '../../actions/remote'; import { fetchTemplate } from '../../actions/template'; -import { getRemoteState, saveRemoteState } from '../../actions/state'; +import ModalPopup from '../basement/Modal'; import Range from './Range'; import Shot from './Shot'; import Step from './Step'; @@ -24,20 +24,23 @@ const mapStateToProps = state => { data: state.remote.payload, error: state.remote.error }, - remoteState: { - data: state.remoteState.payload, - error: state.remoteState.error - }, - template: state.template.payload + //remoteState: { + // data: state.remoteState.payload, + // error: state.remoteState.error + //}, + template: { + data: state.template.payload, + error: state.template.error + } } }; const mapDispatchToProps = (dispatch, props) => ({ - getRemoteState() { - dispatch(getRemoteState(dispatch)) - }, - saveRemoteState(entry) { - dispatch(saveRemoteState(dispatch, entry)) - }, + //getRemoteState() { + // dispatch(getRemoteState(dispatch)) + //}, + //saveRemoteState(entry) { + // dispatch(saveRemoteState(dispatch, entry)) + //}, getRemote() { dispatch(fetchRemote(dispatch)) }, @@ -56,66 +59,78 @@ class RemoteCard extends React.Component { constructor(props) { super(props); this.props.loadTemplate() - this.props.getRemoteState() + //this.props.getRemoteState() + this.props.getRemote() library.add(fas) - } - - // Convert RemoteData to State - dataToState(entry) { - let state = {...this.props.remoteState.data}; - - // Must be deep-copy children nodes - state = { - operation: entry.operation, - mode: entry.mode, - mode_data: {...state.mode_data} - } - - state.mode_data[entry.mode] = { - temp: entry.temp, - fan: entry.fan, - horizontal_vane: entry.horizontal_vane, - vertical_vane: entry.vertical_vane - } - - return state; - } - - // Convert State to Remote - stateToData(m) { - // m: mode - const remoteState = {...this.props.remoteState.data}; - const operation = remoteState['operation']; - const mode = m ? m : remoteState['mode']; - return { - operation: operation, - mode: mode, - ...remoteState['mode_data'][mode], - } + this.remote = {} } render() { //const remote = {...this.state.remote}; - if (!this.props.remoteState.data || !this.props.template) { + //if (!this.props.remote.data || !this.props.template) { + // return ( + //
+ // + // + // + // {'LOADING...'} + // + // + //
+ // ) + //} + + console.log("error entries:") + console.log(this.props.remote.error) + console.log(this.props.template.error) + if (this.props.template.error) { + console.log("Something went wrong. Action will be reverted.") return ( -
- - - - {'LOADING...'} - - -
+ + + Error +
+ } + body={`${this.props.template.error.error}`} + closable={false} + type={'ERROR_MODAL'} + onReload={()=> { + window.location.reload() + //this.props.loadTemplate() + //this.props.getRemote() + } + } + > + ) + //return ( + //
+ //

Something went wrong...

+ //
+ //) } - const remote = this.stateToData(); - - console.log(this.props.remote.error) - console.log(this.props.remoteState.error) + if (this.props.remote.data != null) { + this.remote = {...this.props.remote.data} + } + const remote = this.remote; + //const remote = {...this.props.remote.data}; + console.log(remote) return (
+ { + this.props.remote.error && + + + } + @@ -124,18 +139,18 @@ class RemoteCard extends React.Component { - {true ? : -

- } + }}>Re-Send +
+ {(remote != null && this.props.template.data) != null && { remote.operation = !remote.operation; - this.props.saveRemoteState(this.dataToState(remote)); + //this.props.saveRemoteState(this.dataToState(remote)); this.props.pushRemote(remote) }} - icon={} - /> + icon={} + /> - {remote.temp ? - { - remote.temp = remote.temp + this.props.template[remote.mode].temp.range.step; - this.props.saveRemoteState(this.dataToState(remote)); - this.props.pushRemote(remote) - }} - onDecrement={() => { - remote.temp = remote.temp - this.props.template[remote.mode].temp.range.step; + {remote.temp && + { + remote.temp = remote.temp + this.props.template.data[remote.mode].temp.range.step; + //this.props.saveRemoteState(this.dataToState(remote)); + this.props.pushRemote(remote) + }} + onDecrement={() => { + remote.temp = remote.temp - this.props.template.data[remote.mode].temp.range.step; + //this.props.saveRemoteState(this.dataToState(remote)); + this.props.pushRemote(remote) + }} + /> + } + +
+ + { + if (Object.keys(this.props.template.data).includes(key)) { this.props.saveRemoteState(this.dataToState(remote)); - this.props.pushRemote(remote) - }} - /> :

- } -
-
- - { - if (Object.keys(this.props.template).includes(key)) { - this.props.saveRemoteState(this.dataToState(remote)); - // Get RemoteData from local State - const r = this.stateToData(key); - this.props.saveRemoteState(this.dataToState(r)); - this.props.pushRemote(r) - } - }} - /> - {remote.fan ? - { - console.log('fan') - remote.fan = key - this.props.saveRemoteState(this.dataToState(remote)); - this.props.pushRemote(remote) - }} - /> :

- } -
-
- - {remote.horizontal_vane ? - { - remote.horizontal_vane = key - this.props.saveRemoteState(this.dataToState(remote)); - this.props.pushRemote(remote) - }} - /> :

- } - {remote.vertical_vane ? + // Get RemoteData from local State + const r = this.stateToData(key); + this.props.saveRemoteState(this.dataToState(r)); + this.props.pushRemote(r) + } + }} + /> + {remote.fan && + { + console.log('fan') + remote.fan = key + //this.props.saveRemoteState(this.dataToState(remote)); + this.props.pushRemote(remote) + }} + /> + } +
+
+ + {remote.horizontal_vane && + { + remote.horizontal_vane = key + //this.props.saveRemoteState(this.dataToState(remote)); + this.props.pushRemote(remote) + }} + /> + } + {remote.vertical_vane && { remote.vertical_vane = key - this.props.saveRemoteState(this.dataToState(remote)); + //this.props.saveRemoteState(this.dataToState(remote)); this.props.pushRemote(remote) }} - /> :

- } -
-
-
+ /> + } + + + } +
) } } diff --git a/frontend/src/reducers/template/index.jsx b/frontend/src/reducers/template/index.jsx index 446cdb0..8c4f8b0 100644 --- a/frontend/src/reducers/template/index.jsx +++ b/frontend/src/reducers/template/index.jsx @@ -1,5 +1,6 @@ const initialState = { - payload: null + payload: null, + error: null } export const template = (state = initialState, action) => { switch (action.type) { @@ -13,6 +14,11 @@ export const template = (state = initialState, action) => { ...state, payload: action.payload } + case 'FETCH_TEMPLATE_FAILED': + return { + ...state, + error: action.error + } default: return state } From aea209184e7b64a82b6e289723b4603381ee224c Mon Sep 17 00:00:00 2001 From: Laica Lunasys Date: Wed, 4 Mar 2020 03:06:19 +0900 Subject: [PATCH 3/4] Async sending --- controller/mitsubishi/kgsa3c/controller.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/controller/mitsubishi/kgsa3c/controller.go b/controller/mitsubishi/kgsa3c/controller.go index f3930e1..7faa5d3 100644 --- a/controller/mitsubishi/kgsa3c/controller.go +++ b/controller/mitsubishi/kgsa3c/controller.go @@ -71,9 +71,11 @@ func (c *remoteController) Set(d *models.RemoteData) error { return err } - if err := sender.Send(signal); err != nil { - return err - } + go func() { + if err := sender.Send(signal); err != nil { + panic(err) + } + }() if err := c.database.UpdateState(data); err != nil { return err From a7eada3538b1fa0609cbfa758c3a8adbffe2c65b Mon Sep 17 00:00:00 2001 From: Laica Lunasys Date: Wed, 4 Mar 2020 03:06:55 +0900 Subject: [PATCH 4/4] Fix template solving --- remote/remote.go | 2 ++ server/http.go | 5 +---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/remote/remote.go b/remote/remote.go index abb33c7..e9900d4 100644 --- a/remote/remote.go +++ b/remote/remote.go @@ -13,6 +13,7 @@ type Remote struct { Controller controller.Controller Database controller.Database + Template interface{} } // NewRemote - Initialize Remote @@ -25,6 +26,7 @@ func NewRemote(vendor string, model string, dbPath string) *Remote { if vendor == "mitsubishi" && model == "kgsa3-c" { r.Database = kgsa3c.NewDatabase(vendor, model, dbPath) r.Controller = kgsa3c.EnsureController(r.Database) + r.Template = kgsa3c.TemplateData } return r } diff --git a/server/http.go b/server/http.go index a8f9024..a2331d5 100644 --- a/server/http.go +++ b/server/http.go @@ -8,7 +8,6 @@ import ( "github.com/gin-gonic/gin" "github.com/rakyll/statik/fs" "github.com/sirupsen/logrus" - "github.com/synchthia/remonpi/controller/mitsubishi/kgsa3c" "github.com/synchthia/remonpi/logger" "github.com/synchthia/remonpi/models" "github.com/synchthia/remonpi/remote" @@ -115,7 +114,5 @@ func (h *httpServer) postRemote(c *gin.Context) { } func (h *httpServer) getTemplate(c *gin.Context) { - if h.Remote.Vendor == "mitsubishi" && h.Remote.Model == "kgsa3-c" { - c.JSON(http.StatusOK, kgsa3c.TemplateData) - } + c.JSON(http.StatusOK, h.Remote.Template) }