diff --git a/app/package.json b/app/package.json index 71b0757..581b6c3 100644 --- a/app/package.json +++ b/app/package.json @@ -20,6 +20,8 @@ "axios": "^0.19.2", "babel-eslint": "^10.0.3", "compression-webpack-plugin": "^3.1.0", + "countries-and-timezones": "^2.2.0", + "countries-list": "^2.5.4", "eslint": "^6.7.2", "eslint-plugin-vue": "^6.1.2", "sass": "^1.19.0", diff --git a/app/src/assets/fantasyNames.json b/app/src/assets/fantasyNames.json new file mode 100644 index 0000000..4ee9e56 --- /dev/null +++ b/app/src/assets/fantasyNames.json @@ -0,0 +1,302 @@ +[ + "Lydan", + "Syrin", + "Ptorik", + "Joz", + "Varog", + "Gethrod ", + "Hezra", + "Feron ", + "Ophni ", + "Colborn ", + "Fintis ", + "Gatlin", + "Jinto", + "Hagalbar", + "Krinn", + "Lenox", + "Revvyn", + "Hodus", + "Dimian", + "Paskel", + "Kontas", + "Weston", + "Azamarr ", + "Jather ", + "Tekren ", + "Jareth ", + "Adon", + "Zaden ", + "Eune ", + "Graff ", + "Tez ", + "Jessop ", + "Gunnar ", + "Pike ", + "Domnhar ", + "Baske ", + "Jerrick", + "Mavrek", + "Riordan ", + "Wulfe", + "Straus ", + "Tyvrik ", + "Henndar ", + "Favroe ", + "Whit ", + "Jaris ", + "Renham", + "Kagran ", + "Lassrin ", + "Vadim", + "Arlo ", + "Quintis ", + "Vale ", + "Caelan ", + "Yorjan ", + "Khron ", + "Ishmael", + "Jakrin ", + "Fangar ", + "Roux", + "Baxar ", + "Hawke ", + "Gatlen ", + "Barak ", + "Nazim ", + "Kadric ", + "Paquin", + "Kent ", + "Moki ", + "Rankar ", + "Lothe ", + "Ryven ", + "Clawsen ", + "Pakker ", + "Embre ", + "Cassian", + "Verssek ", + "Dagfinn ", + "Ebraheim ", + "Nesso ", + "Eldermar ", + "Rivik ", + "Rourke ", + "Barton ", + "Hemm ", + "Sarkin ", + "Blaiz ", + "Talon", + "Agro", + "Zagaroth", + "Turrek", + "Esdel", + "Lustros ", + "Zenner ", + "Baashar ", + "Dagrod ", + "Gentar ", + "Feston ", + "Syrana ", + "Resha ", + "Varin ", + "Wren ", + "Yuni ", + "Talis ", + "Kessa ", + "Magaltie ", + "Aeris ", + "Desmina ", + "Krynna ", + "Asralyn ", + "Herra ", + "Pret ", + "Kory ", + "Afia ", + "Tessel ", + "Rhiannon ", + "Zara ", + "Jesi", + "Belen ", + "Rei ", + "Ciscra ", + "Temy ", + "Renalee ", + "Estyn ", + "Maarika ", + "Lynorr ", + "Tiv ", + "Annihya ", + "Semet ", + "Tamrin ", + "Antia ", + "Reslyn ", + "Basak", + "Vixra ", + "Pekka ", + "Xavia ", + "Beatha ", + "Yarri", + "Liris ", + "Sonali ", + "Razra ", + "Soko ", + "Maeve ", + "Everen ", + "Yelina ", + "Morwena ", + "Hagar ", + "Palra ", + "Elysa ", + "Sage ", + "Ketra ", + "Lynx ", + "Agama ", + "Thesra ", + "Tezani ", + "Ralia ", + "Esmee ", + "Heron", + "Naima ", + "Rydna ", + "Sparrow ", + "Baakshi ", + "Ibera", + "Phlox", + "Dessa", + "Braithe ", + "Taewen", + "Larke", + "Silene", + "Phressa", + "Esther ", + "Anika ", + "Rasy ", + "Harper ", + "Indie ", + "Vita ", + "Drusila ", + "Minha ", + "Surane ", + "Lassona ", + "Merula ", + "Kye ", + "Jonna ", + "Lyla ", + "Zet ", + "Orett ", + "Naphtalia ", + "Turi ", + "Rhays ", + "Shike ", + "Hartie ", + "Beela ", + "Leska ", + "Vemery ", + "Lunex ", + "Fidess ", + "Tisette ", + "Partha", + "Noble Crest Stables", + "Gibb’s Farm", + "Triple Axes Pub", + "Arrowhead Inn", + "Yeomen’s Manor", + "Bootstraps & Buckles Cobbler", + "Dwarf’s Gullet Tavern", + "Hollowvale Village", + "Thunder Hoof Stables", + "Clipper’s County", + "Gresgo’s Pond ", + "Hemm’s Tailors ", + "Ditch’n’Dagger Tavern ", + "Twin Horses Lake Town", + "Boggs Landing", + "Heatherstown Village", + "Trekker’s Square ", + "Embris Hollow ", + "Zagoroth Mountain Town ", + "Padsley Village ", + "Sleeping Dragon Inn", + "Ramoth Lye Creek", + "Dragmire Drove ", + "Archer’s Ale House ", + "Peeker’s Valley ", + "Anvil & Flint Blacksmithery", + "Pale Thorn Cove ", + "Fang Peak ", + "Arc of the Holy Shield Monastery ", + "Breggo’s Beard Brewery ", + "Golden Stalk Granary ", + "Saw and Splinter’s Woodshop ", + "Siren’s Shipyard ", + "Silver Fin Fishery ", + "Addler’s Drove ", + "Black Morrow Marshes ", + "Shepherd’s Field ", + "Honeyclover Meadow ", + "Finch & Fox Inn ", + "The Warren Pub ", + "Fennel & Fallow Bakery ", + "Rose & Crown Tavern ", + "Knight’s Motte and Bailey ", + "White Elk Hall ", + "Briar Bridge Village", + "Mighty Hart Furriers", + "Ekhart Bridge", + "The Magpie’s Market ", + "Thresh’s Cove ", + "Denmarrow Mountains ", + "Simple Beasts Watering Hole ", + "Lowly Strider Almshouse ", + "Miss Plunkerhouse’s Grand Tailors", + "White Lion Halls", + "Thousand Lanterns Inn", + "Wild Hare Country Tavern", + "Laskerville Village ", + "Scout’s Towers", + "Golden Longbow Fields", + "Tuckborrow Village", + "Trader’s Turn Plaza", + " Stoneburrow Town", + "Brather’s Town", + "Stout Dragon Tavern", + "Dueling Swords Blacksmithery", + "The Braided Plait Bakery", + "Mossy Stone Cove", + "Fairy Winds Beach", + "Old Stone Giant Mill", + "Sacred Scroll Holy ", + "King Rothenham Square", + "Brewer’s Bounty Alehouse", + "Oslocrest Town", + "Parsca’s Plaza", + "Old Mayfield Farms", + "Fowler’s Prize Furrers", + "Iron Halberd Smithy", + "Dukes Valley", + "Burrowing Badger Inn", + "Pork Belly’s Butcher Shop", + "Cast Iron Almshouse", + "Three Braided Beards Tavern", + "King’s Own Tailors", + "County Arms Smithy", + "Golden Rise Bakery", + "Spotted Finch Meadows", + "Fairy Sisters Pasture", + "Twin Owls Inn ", + "Snow Bard Village", + "DarkVale Valley", + "Tallard’s Orchards ", + "Two Moons Cove ", + "Star Fin Shipyard", + "White Wind Mill Bakery", + "Troll’s Hand Masons", + "Vatrecastle Village", + "Archer’s Arm Tavern", + "Throne of the Ancient One Temple", + "Swift Axes Woodcutter Shoppe ", + "Evenly Yoked Stables", + "Open Hands Almshouse", + "Far Wren Village" + ] \ No newline at end of file diff --git a/app/src/assets/witcherNames.json b/app/src/assets/witcherNames.json new file mode 100644 index 0000000..733e017 --- /dev/null +++ b/app/src/assets/witcherNames.json @@ -0,0 +1,142 @@ +[ + "Innkeeper", + "Abigail", + "Adda the White", + "Alina", + "Alvin", + "Andrew Gablodda", + "Angus", + "Antoinette", + "Armorer", + "Azar Javed", + "Berengar", + "Bogut Kuternoga", + "Boholt", + "Bookseller", + "Bootblack (Vizima)", + "Brogg", + "Buse", + "Butter Bean", + "Carmen", + "Caroline", + "Celina", + "Chireadan", + "City Guard", + "Coccacidium", + "Coleman", + "Con artist", + "Conrad", + "Corbin", + "Dandelion", + "Declan Leuvaarden", + "Erkyn Blunt", + "Eskel", + "Fat Fred", + "Fence", + "Ferryman", + "Fisher King (lover of Lady of the Lake)", + "Foltest", + "Franz Kniprode", + "Friendly vodyan priest", + "Gambling ghost", + "Gardener", + "Gellert Bleinheim", + "Geralt of Rivia", + "Golan Vivaldi", + "Grandma", + "Gravedigger (Vizima)", + "Greater cockatrice", + "Half-elf", + "Halfar", + "Haren Brogg", + "Havekar", + "Herbalist", + "Hermit", + "Hierophant", + "Hildegard Zollstock", + "Ida Vertz", + "Ilsa", + "Jacques de Aldersberg", + "Jean-Pierre", + "Jester", + "Jethro", + "Juan Pablo Vassermiller", + "Julian", + "Kalkstein", + "King of the Wild Hunt", + "Kobus de Vollen", + "Kristina", + "Lambert", + "Leo", + "Lilly", + "Lowlife", + "Mage", + "Maggot", + "Malcolm Stein", + "Marcus Vertz", + "Mason Harn", + "Meis", + "Midday bride", + "Mikul", + "Moa", + "Morenn", + "Munro Bruys", + "Murky Waters blacksmith", + "Murky Waters healer", + "Mysterious assassin", + "Mysterious man", + "Nadir", + "Naiad (Murky Waters lakeside)", + "Novice nun", + "Odo (merchant)", + "Ori Reuven", + "Ozzrel", + "Pat", + "Patrick de Weyze", + "Philippa Eilhart", + "Professor (assassin)", + "Radovid V", + "Ramerot", + "Ramsmeat", + "Raven", + "Rayla", + "Raymond Maarloeve", + "Ren Grouver", + "Resolute girl", + "Reverend (Outskirts)", + "The Rock", + "Roderick de Wett", + "Roland Bleinheim", + "Royal huntsman", + "Saint Gregory", + "Savolla", + "Scoia'tael quartermaster", + "Shani", + "Siegfried of Denesle", + "Swordsmith", + "Teyu", + "Thaler (spy)", + "Tobias Hoffman", + "Torch Guardian", + "Toruviel", + "Townsfolk", + "Trader", + "Triss Merigold", + "Ureus", + "Vaska", + "Velerad", + "Vertz", + "Vesemir", + "Vesna Hood", + "Vesper", + "Vetala", + "Vincent Meis", + "Voref", + "Yaevinn", + "Yamo Ryeboozer", + "Yaren Bolt", + "Zahin Schmartz", + "Zdenek", + "Zephyr", + "Zoltan Chivay" + ] \ No newline at end of file diff --git a/app/src/components/SetupWeather.vue b/app/src/components/SetupWeather.vue new file mode 100644 index 0000000..96f89f7 --- /dev/null +++ b/app/src/components/SetupWeather.vue @@ -0,0 +1,47 @@ + + + diff --git a/app/src/components/SetupWifiConnect.vue b/app/src/components/SetupWifiConnect.vue new file mode 100644 index 0000000..42882d5 --- /dev/null +++ b/app/src/components/SetupWifiConnect.vue @@ -0,0 +1,61 @@ + + + diff --git a/app/src/components/WeatherFindLocation.vue b/app/src/components/WeatherFindLocation.vue index 7559fb8..e4d276f 100644 --- a/app/src/components/WeatherFindLocation.vue +++ b/app/src/components/WeatherFindLocation.vue @@ -39,7 +39,7 @@ export default { props: { location: { type: Number, - required: true + required: false }, api: { type: String, diff --git a/app/src/plugins/vuetify.js b/app/src/plugins/vuetify.js index 88bccd4..5ab13ce 100644 --- a/app/src/plugins/vuetify.js +++ b/app/src/plugins/vuetify.js @@ -8,15 +8,15 @@ const MY_ICONS = { // system icons //complete: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/check/baseline.svg')}, //cancel: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/cancel/baseline.svg')}, - //close: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/close/baseline.svg')}, + close: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/close/baseline.svg')}, //delete: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/delete/baseline.svg')}, //clear: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/clear/baseline.svg')}, //success: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/check_circle/baseline.svg')}, //info: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/info/baseline.svg')}, //warning: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/priority_high/baseline.svg')}, //error: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/warning/baseline.svg')}, - //prev: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/chevron_left/baseline.svg')}, - //next: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/chevron_right/baseline.svg')}, + prev: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/chevron_left/baseline.svg')}, + next: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/chevron_right/baseline.svg')}, //checkboxOn: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/check_box/baseline.svg')}, //checkboxOff: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/check_box_outline_blank/baseline.svg')}, //checkboxIndeterminate: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/indeterminate_check_box/baseline.svg')}, @@ -26,8 +26,8 @@ const MY_ICONS = { //menu: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/menu/baseline.svg')}, //subgroup: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/arrow_drop_down/baseline.svg')}, dropdown: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/arrow_drop_down/baseline.svg')}, - //radioOn: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/radio_button_checked/baseline.svg')}, - //radioOff: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/radio_button_unchecked/baseline.svg')}, + radioOn: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/radio_button_checked/baseline.svg')}, + radioOff: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/radio_button_unchecked/baseline.svg')}, //edit: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/edit/baseline.svg')}, //ratingEmpty: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/star_border/baseline.svg')}, //ratingFull: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/star/baseline.svg')}, @@ -47,6 +47,7 @@ const MY_ICONS = { //preview: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/remove_red_eye/baseline.svg')}, //search: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/search/baseline.svg')}, memory: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/memory/baseline.svg')}, + lock: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/lock/baseline.svg')}, // wifi signalWifi0: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_0_bar/baseline.svg')}, @@ -57,7 +58,13 @@ const MY_ICONS = { signalWifi3: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_3_bar/baseline.svg')}, signalWifi3Lock: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_3_bar_lock/baseline.svg')}, signalWifi4: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_4_bar/baseline.svg')}, - signalWifi4Lock: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_4_bar_lock/baseline.svg')} + signalWifi4Lock: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_4_bar_lock/baseline.svg')}, + + // setup + wb_sunny: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/wb_sunny/baseline.svg')}, + open_in_new: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/open_in_new/baseline.svg')}, + face: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/face/baseline.svg')}, + autorenew: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/autorenew/baseline.svg')} } diff --git a/app/src/router/index.js b/app/src/router/index.js index 3d93aca..0cf8c43 100644 --- a/app/src/router/index.js +++ b/app/src/router/index.js @@ -3,18 +3,30 @@ import VueRouter from 'vue-router' const Dashboard = () => import('../views/Dashboard') const Settings = () => import('../views/Settings') -//const Wifi = () => import(/* webpackChunkName: "wifi" */ '../views/Wifi') -//const Sandbox = () => import(/* webpackChunkName: "sandbox" */ '../views/Sandbox') +const SetupStart = () => import('../views/Setup/Start') +const SetupCountry = () => import('../views/Setup/Country') +const SetupWifi = () => import('../views/Setup/Wifi') +const SetupWeather = () => import('../views/Setup/Weather') +const SetupName = () => import('../views/Setup/Name') +const SetupAppearance = () => import('../views/Setup/Appearance') +const SetupDone = () => import('../views/Setup/Done') Vue.use(VueRouter); export default new VueRouter({ routes: [ { path: '/', component: Dashboard }, - { path: '/settings', component: Settings, meta: { transitionName: 'slide' } }, - //{ path: '/wifi', component: Wifi }, - //{ path: '/sandbox', component: Sandbox }, + { path: '/settings', component: Settings, meta: { transitionName: 'slide' } }, + + // setup wizard + { path: '/setup/start', component: SetupStart, meta: { transitionName: 'slide' } }, + { path: '/setup/country', component: SetupCountry, meta: { transitionName: 'slide' } }, + { path: '/setup/wifi', component: SetupWifi, meta: { transitionName: 'slide' } }, + { path: '/setup/weather', component: SetupWeather, meta: { transitionName: 'slide' } }, + { path: '/setup/name', component: SetupName, meta: { transitionName: 'slide' } }, + { path: '/setup/appearance', component: SetupAppearance, meta: { transitionName: 'slide' } }, + { path: '/setup/done', component: SetupDone, meta: { transitionName: 'slide' } }, { path: '*', redirect: '/' } ], diff --git a/app/src/views/Setup/Appearance.vue b/app/src/views/Setup/Appearance.vue new file mode 100644 index 0000000..9003bee --- /dev/null +++ b/app/src/views/Setup/Appearance.vue @@ -0,0 +1,50 @@ + + + \ No newline at end of file diff --git a/app/src/views/Setup/Country.vue b/app/src/views/Setup/Country.vue new file mode 100644 index 0000000..901c44b --- /dev/null +++ b/app/src/views/Setup/Country.vue @@ -0,0 +1,114 @@ + + + \ No newline at end of file diff --git a/app/src/views/Setup/Done.vue b/app/src/views/Setup/Done.vue new file mode 100644 index 0000000..c9f920b --- /dev/null +++ b/app/src/views/Setup/Done.vue @@ -0,0 +1,36 @@ + + + \ No newline at end of file diff --git a/app/src/views/Setup/Name.vue b/app/src/views/Setup/Name.vue new file mode 100644 index 0000000..08d8b1a --- /dev/null +++ b/app/src/views/Setup/Name.vue @@ -0,0 +1,98 @@ + + + + + \ No newline at end of file diff --git a/app/src/views/Setup/Start.vue b/app/src/views/Setup/Start.vue new file mode 100644 index 0000000..78c2f0d --- /dev/null +++ b/app/src/views/Setup/Start.vue @@ -0,0 +1,116 @@ + + + + + + diff --git a/app/src/views/Setup/Weather.vue b/app/src/views/Setup/Weather.vue new file mode 100644 index 0000000..5de8336 --- /dev/null +++ b/app/src/views/Setup/Weather.vue @@ -0,0 +1,91 @@ + + + \ No newline at end of file diff --git a/app/src/views/Setup/Wifi.vue b/app/src/views/Setup/Wifi.vue new file mode 100644 index 0000000..cf40fb1 --- /dev/null +++ b/app/src/views/Setup/Wifi.vue @@ -0,0 +1,82 @@ + + + \ No newline at end of file diff --git a/src/app.cpp b/src/app.cpp index 3d502cd..a073bb4 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -136,8 +136,17 @@ void setupSettingsGet() AsyncResponseStream *response = request->beginResponseStream("application/json"); DynamicJsonDocument root(1024); - root["device"]["angle"] = NVS.getInt("device.angle"); + root["system"]["country"] = NVS.getString("system.country"); + root["system"]["language"] = NVS.getString("system.language"); + root["system"]["timezone"] = NVS.getString("system.timezone"); + root["system"]["utc"] = NVS.getInt("system.utc"); + root["system"]["dst"] = NVS.getInt("system.dst"); + // gmtOffset_sec + // daylightOffset_sec + + //root["device"]["angle"] = NVS.getInt("device.angle"); root["device"]["theme"] = NVS.getString("device.theme"); + root["device"]["name"] = NVS.getString("device.name"); root["playlist"]["timer"] = NVS.getInt("playlist.timer"); @@ -146,9 +155,9 @@ void setupSettingsGet() root["weather"]["lang"] = NVS.getString("weather.lang"); root["weather"]["unit"] = NVS.getString("weather.unit"); - root["cloud"]["mode"] = NVS.getString("cloud.mode"); - root["cloud"]["url"] = NVS.getString("cloud.url"); - root["cloud"]["token"] = NVS.getString("cloud.token"); + //root["cloud"]["mode"] = NVS.getString("cloud.mode"); + //root["cloud"]["url"] = NVS.getString("cloud.url"); + //root["cloud"]["token"] = NVS.getString("cloud.token"); serializeJson(root, *response); request->send(response); @@ -170,19 +179,39 @@ void setupSettingsPost() } else { - NVS.setInt("device.angle", doc["device"]["angle"].as()); - NVS.setString("device.theme", doc["device"]["theme"]); + JsonVariant system = doc["system"]; + if (!system.isNull()) { + NVS.setString("system.country", system["country"]); + NVS.setString("system.language", system["language"]); + NVS.setString("system.timezone", system["timezone"]); + NVS.setInt("system.utc", system["utc"].as()); + NVS.setInt("system.dst", system["dst"].as()); + } - NVS.setInt("playlist.timer", doc["playlist"]["timer"].as()); + JsonVariant device = doc["device"]; + if (!device.isNull()) { + NVS.setInt("device.angle", device["angle"].as()); + NVS.setString("device.theme", device["theme"]); + NVS.setString("device.name", device["name"]); + } - NVS.setString("weather.api", doc["weather"]["api"]); - NVS.setInt("weather.loc", doc["weather"]["location"].as()); - NVS.setString("weather.lang", doc["weather"]["lang"]); - NVS.setString("weather.unit", doc["weather"]["unit"]); + JsonVariant playlist = doc["playlist"]; + if (!playlist.isNull()) { + NVS.setInt("playlist.timer", playlist["timer"].as()); + } + JsonVariant weather = doc["weather"]; + if (!doc["weather"].isNull()) { + NVS.setString("weather.api", weather["api"]); + NVS.setInt("weather.loc", weather["location"].as()); + NVS.setString("weather.lang", weather["lang"]); + NVS.setString("weather.unit", weather["unit"]); + } +/* NVS.setString("cloud.mode", doc["cloud"]["mode"]); NVS.setString("cloud.url", doc["cloud"]["url"]); NVS.setString("cloud.token", doc["cloud"]["token"]); + */ NVS.commit(); @@ -442,8 +471,7 @@ void setupOTA() AsyncWebServerResponse *response = request->beginResponse(200, "application/ld+json; charset=utf-8", shouldReboot ? "{\"success\": true}" : "{\"success\": false}"); response->addHeader("Connection", "close"); - request->send(response); - }, + request->send(response); }, [](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { if (!index) {