summaryrefslogtreecommitdiff
path: root/watchos/InfiniSolar/InfiniSolar WatchKit Extension
diff options
context:
space:
mode:
Diffstat (limited to 'watchos/InfiniSolar/InfiniSolar WatchKit Extension')
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json28
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Contents.json53
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json28
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json18
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json18
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json18
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json28
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json18
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json28
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json28
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Contents.json6
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/ComplicationController.swift59
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/ContentView.swift22
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/GenerationView.swift67
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/InfiniSolarApp.swift43
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/Info.plist38
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterGenerationState.swift114
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterState.swift78
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterStatus.swift29
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterView.swift75
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/NotificationController.swift33
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/NotificationView.swift20
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/Preview Content/Preview Assets.xcassets/Contents.json6
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/PumpState.swift86
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/PumpView.swift60
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/PushNotificationPayload.apns20
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/RoomState.swift84
-rw-r--r--watchos/InfiniSolar/InfiniSolar WatchKit Extension/RoomView.swift42
28 files changed, 1147 insertions, 0 deletions
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json
new file mode 100644
index 0000000..ed7de25
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json
@@ -0,0 +1,28 @@
+{
+ "images" : [
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : "<=145"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">161"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">145"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">183"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Contents.json b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Contents.json
new file mode 100644
index 0000000..e8b3252
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Contents.json
@@ -0,0 +1,53 @@
+{
+ "assets" : [
+ {
+ "filename" : "Circular.imageset",
+ "idiom" : "watch",
+ "role" : "circular"
+ },
+ {
+ "filename" : "Extra Large.imageset",
+ "idiom" : "watch",
+ "role" : "extra-large"
+ },
+ {
+ "filename" : "Graphic Bezel.imageset",
+ "idiom" : "watch",
+ "role" : "graphic-bezel"
+ },
+ {
+ "filename" : "Graphic Circular.imageset",
+ "idiom" : "watch",
+ "role" : "graphic-circular"
+ },
+ {
+ "filename" : "Graphic Corner.imageset",
+ "idiom" : "watch",
+ "role" : "graphic-corner"
+ },
+ {
+ "filename" : "Graphic Extra Large.imageset",
+ "idiom" : "watch",
+ "role" : "graphic-extra-large"
+ },
+ {
+ "filename" : "Graphic Large Rectangular.imageset",
+ "idiom" : "watch",
+ "role" : "graphic-large-rectangular"
+ },
+ {
+ "filename" : "Modular.imageset",
+ "idiom" : "watch",
+ "role" : "modular"
+ },
+ {
+ "filename" : "Utilitarian.imageset",
+ "idiom" : "watch",
+ "role" : "utilitarian"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json
new file mode 100644
index 0000000..ed7de25
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json
@@ -0,0 +1,28 @@
+{
+ "images" : [
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : "<=145"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">161"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">145"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">183"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json
new file mode 100644
index 0000000..9685a7f
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json
@@ -0,0 +1,18 @@
+{
+ "images" : [
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">161"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">183"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json
new file mode 100644
index 0000000..9685a7f
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json
@@ -0,0 +1,18 @@
+{
+ "images" : [
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">161"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">183"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json
new file mode 100644
index 0000000..9685a7f
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json
@@ -0,0 +1,18 @@
+{
+ "images" : [
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">161"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">183"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json
new file mode 100644
index 0000000..ed7de25
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json
@@ -0,0 +1,28 @@
+{
+ "images" : [
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : "<=145"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">161"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">145"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">183"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json
new file mode 100644
index 0000000..9685a7f
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json
@@ -0,0 +1,18 @@
+{
+ "images" : [
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">161"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">183"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json
new file mode 100644
index 0000000..ed7de25
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json
@@ -0,0 +1,28 @@
+{
+ "images" : [
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : "<=145"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">161"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">145"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">183"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json
new file mode 100644
index 0000000..ed7de25
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json
@@ -0,0 +1,28 @@
+{
+ "images" : [
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : "<=145"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">161"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">145"
+ },
+ {
+ "idiom" : "watch",
+ "scale" : "2x",
+ "screen-width" : ">183"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Contents.json b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/ComplicationController.swift b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/ComplicationController.swift
new file mode 100644
index 0000000..7538d60
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/ComplicationController.swift
@@ -0,0 +1,59 @@
+//
+// ComplicationController.swift
+// InfiniSolar WatchKit Extension
+//
+// Created by Evgeny Zinoviev on 03.08.2021.
+//
+
+import ClockKit
+
+
+class ComplicationController: NSObject, CLKComplicationDataSource {
+
+ // MARK: - Complication Configuration
+
+ func getComplicationDescriptors(handler: @escaping ([CLKComplicationDescriptor]) -> Void) {
+ let descriptors = [
+ CLKComplicationDescriptor(identifier: "complication", displayName: "InfiniSolar", supportedFamilies: CLKComplicationFamily.allCases)
+ // Multiple complication support can be added here with more descriptors
+ ]
+
+ // Call the handler with the currently supported complication descriptors
+ handler(descriptors)
+ }
+
+ func handleSharedComplicationDescriptors(_ complicationDescriptors: [CLKComplicationDescriptor]) {
+ // Do any necessary work to support these newly shared complication descriptors
+ }
+
+ // MARK: - Timeline Configuration
+
+ func getTimelineEndDate(for complication: CLKComplication, withHandler handler: @escaping (Date?) -> Void) {
+ // Call the handler with the last entry date you can currently provide or nil if you can't support future timelines
+ handler(nil)
+ }
+
+ func getPrivacyBehavior(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationPrivacyBehavior) -> Void) {
+ // Call the handler with your desired behavior when the device is locked
+ handler(.showOnLockScreen)
+ }
+
+ // MARK: - Timeline Population
+
+ func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {
+ // Call the handler with the current timeline entry
+ handler(nil)
+ }
+
+ func getTimelineEntries(for complication: CLKComplication, after date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
+ // Call the handler with the timeline entries after the given date
+ handler(nil)
+ }
+
+ // MARK: - Sample Templates
+
+ func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
+ // This method will be called once per supported complication, and the results will be cached
+ handler(nil)
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/ContentView.swift b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/ContentView.swift
new file mode 100644
index 0000000..49be4e2
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/ContentView.swift
@@ -0,0 +1,22 @@
+//
+// ContentView.swift
+// InfiniSolar WatchKit Extension
+//
+// Created by Evgeny Zinoviev on 03.08.2021.
+//
+//
+//import SwiftUI
+//
+//struct ContentView: View {
+// var body: some View {
+// MainInverterView()
+//
+//
+// }
+//}
+//
+//struct ContentView_Previews: PreviewProvider {
+// static var previews: some View {
+// ContentView()
+// }
+//}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/GenerationView.swift b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/GenerationView.swift
new file mode 100644
index 0000000..f9d9c5e
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/GenerationView.swift
@@ -0,0 +1,67 @@
+//
+// GenerationView.swift
+// InfiniSolar WatchKit Extension
+//
+// Created by Evgeny Zinoviev on 08.08.2021.
+//
+
+import SwiftUI
+
+struct GenerationView: View {
+ @ObservedObject var state = InverterGenerationState()
+
+ var body: some View {
+ VStack(alignment: .leading) {
+ Text("Generation")
+ .font(.title2)
+ .fontWeight(.thin)
+ Spacer().frame(height: 10)
+
+ if self.state.failed == true {
+ Text("Error while fetching info.")
+ .multilineTextAlignment(.leading)
+
+ Spacer().frame(height: 10)
+
+ Button(action:{
+ self.state.fetch()
+ }) {
+ Text("Retry")
+ }
+ } else if !self.state.done {
+ ProgressView().progressViewStyle(CircularProgressViewStyle())
+ } else {
+ Text("Today: ")
+ + Text(String(self.state.today) + " Wh").fontWeight(.thin)
+
+ if self.state.yesterday > 0 {
+ Spacer().frame(height: 5)
+ Text("Yesterday: ")
+ + Text(String(self.state.yesterday) + " Wh").fontWeight(.thin)
+ }
+
+ if self.state.dayBeforeYesterday > 0 {
+ Spacer().frame(height: 5)
+ Text("The day before yesterday: ")
+ + Text(String(self.state.dayBeforeYesterday) + " Wh").fontWeight(.thin)
+ }
+ }
+ }.frame(
+ minWidth: 0,
+ maxWidth: .infinity,
+ minHeight: 0,
+ maxHeight: .infinity,
+ alignment: .topLeading
+ ).onAppear() {
+ self.state.fetch()
+ }.onDisappear() {
+ self.state.stop()
+ }
+ }
+}
+
+struct GenerationView_Previews: PreviewProvider {
+ static var previews: some View {
+ GenerationView()
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InfiniSolarApp.swift b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InfiniSolarApp.swift
new file mode 100644
index 0000000..c6371b4
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InfiniSolarApp.swift
@@ -0,0 +1,43 @@
+//
+// InfiniSolarApp.swift
+// InfiniSolar WatchKit Extension
+//
+// Created by Evgeny Zinoviev on 03.08.2021.
+//
+
+import SwiftUI
+
+@main
+struct InfiniSolarApp: App {
+ @SceneBuilder var body: some Scene {
+ WindowGroup {
+ NavigationView {
+ ScrollView(.vertical) {
+ VStack(alignment: .leading) {
+ InverterView()
+ self.divider()
+
+ RoomView()
+ self.divider()
+
+ PumpView()
+ }
+ .frame(
+ minWidth: 0,
+ maxWidth: .infinity,
+ minHeight: 0,
+ maxHeight: .infinity,
+ alignment: .topLeading
+ )
+ }
+ }
+ }
+
+ WKNotificationScene(controller: NotificationController.self, category: "myCategory")
+ }
+
+ func divider() -> some View {
+ return Divider()
+ .padding(EdgeInsets(top: 12, leading: 4, bottom: 12, trailing: 4))
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Info.plist b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Info.plist
new file mode 100644
index 0000000..916e798
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Info.plist
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleDisplayName</key>
+ <string>InfiniSolar WatchKit Extension</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>CLKComplicationPrincipalClass</key>
+ <string>$(PRODUCT_MODULE_NAME).ComplicationController</string>
+ <key>NSExtension</key>
+ <dict>
+ <key>NSExtensionAttributes</key>
+ <dict>
+ <key>WKAppBundleIdentifier</key>
+ <string>io.ch1p.InfiniSolar.watchkitapp</string>
+ </dict>
+ <key>NSExtensionPointIdentifier</key>
+ <string>com.apple.watchkit</string>
+ </dict>
+ <key>WKWatchOnly</key>
+ <true/>
+</dict>
+</plist>
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterGenerationState.swift b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterGenerationState.swift
new file mode 100644
index 0000000..bbd9d4c
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterGenerationState.swift
@@ -0,0 +1,114 @@
+//
+// InverterGenerationState.swift
+// InfiniSolar WatchKit Extension
+//
+// Created by Evgeny Zinoviev on 08.08.2021.
+//
+
+import Alamofire
+import SwiftyJSON
+
+extension Date {
+ static var yesterday: Date { return Date().dayBefore }
+ static var beforeYesterday: Date { return Date().dayBefore2 }
+ var dayBefore: Date {
+ return Calendar.current.date(byAdding: .day, value: -1, to: noon)!
+ }
+ var dayBefore2: Date {
+ return Calendar.current.date(byAdding: .day, value: -2, to: noon)!
+ }
+ var noon: Date {
+ return Calendar.current.date(bySettingHour: 12, minute: 0, second: 0, of: self)!
+ }
+ var month: Int {
+ return Calendar.current.component(.month, from: self)
+ }
+}
+
+public class InverterGenerationState: ObservableObject {
+ @Published var today: Int
+ @Published var yesterday: Int
+ @Published var dayBeforeYesterday: Int
+ @Published var failed: Bool
+
+ var request: DataRequest?
+ var done: Bool
+
+ init() {
+ self.request = nil
+ self.today = 0
+ self.yesterday = 0
+ self.dayBeforeYesterday = 0
+ self.failed = false
+ self.done = false
+ }
+
+ func fetch() {
+ let today = Date()
+ let yesterday = Date.yesterday
+ let dayBeforeYesterday = Date.beforeYesterday
+
+ let cToday = Calendar.current.dateComponents([.day, .month, .year], from: today)
+ let cYday1 = Calendar.current.dateComponents([.day, .month, .year], from: yesterday)
+ let cYday2 = Calendar.current.dateComponents([.day, .month, .year], from: dayBeforeYesterday)
+
+ // shit, this looks like javascript in 2005 :(
+ // but it's my second day using swift, please treat me easy lol
+
+ // load today
+ self.getDayGenerated(arguments: [cToday.year!, cToday.month!, cToday.day!]) { wh in
+ self.today = wh
+ if cToday.month == cYday1.month {
+ // load yesterday
+ self.getDayGenerated(arguments: [cYday1.year!, cYday1.month!, cYday1.day!]) { wh in
+ self.yesterday = wh
+ if cToday.month == cYday2.month {
+ // load the day before yesterday
+ self.getDayGenerated(arguments: [cYday2.year!, cYday2.month!, cYday2.day!]) { wh in
+ self.dayBeforeYesterday = wh
+ self.done = true
+ }
+ } else {
+ self.done = true
+ }
+ }
+ } else {
+ self.done = true
+ }
+ }
+ }
+
+ func getDayGenerated(arguments: [Int], onComplete: @escaping (Int) -> ()) {
+ let args = arguments.map(String.init)
+ .joined(separator: ",")
+
+ self.request = AF.request("http://192.168.5.223:8380/get-day-generated/?args="+args).responseJSON { response in
+ self.request = nil
+
+ switch response.result {
+ case .success(let value):
+ let json = JSON(value)
+ onComplete(json["data"]["wh"].int ?? 0)
+
+ case .failure(let error):
+ switch (error) {
+ case .explicitlyCancelled:
+ print("InverterGenerationState: request has been canceled")
+ break
+
+ default:
+ print("InverterGenerationState: oops, something failed")
+ print(error)
+ self.failed = true
+ }
+ }
+ }
+ }
+
+ func stop() {
+ if self.request != nil {
+ self.request?.cancel()
+ self.request = nil
+ }
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterState.swift b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterState.swift
new file mode 100644
index 0000000..cd6d5fa
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterState.swift
@@ -0,0 +1,78 @@
+//
+// InverterStatusFetcher.swift
+// InfiniSolar WatchKit Extension
+//
+// Created by Evgeny Zinoviev on 03.08.2021.
+//
+
+import Alamofire
+import SwiftyJSON
+
+public class InverterState: ObservableObject {
+ @Published var status: InverterStatus
+ @Published var fetchError: Bool = false
+
+ var timer: Timer?
+ var request: DataRequest?
+
+ func startFetching() {
+ if self.timer != nil {
+ self.stopFetching()
+ }
+
+ self.timer = Timer.scheduledTimer(timeInterval: 1,
+ target: self,
+ selector: #selector(fetchStatus),
+ userInfo: nil,
+ repeats: true)
+// self.timer?.fire()
+ }
+
+ func stopFetching() {
+ if self.request != nil {
+ self.request?.cancel()
+ self.request = nil
+ }
+
+ self.fetchError = false
+ self.timer?.invalidate()
+ self.timer = nil
+ }
+
+ @objc func fetchStatus() {
+ self.fetchError = false
+
+ self.request = AF.request("http://192.168.5.223:8380/get-status/").responseJSON {
+ response in
+ switch response.result {
+ case .success(let value):
+ let json = JSON(value)
+ self.status.activePower = json["data"]["ac_output_active_power"]["value"].int ?? 0
+ self.status.batteryVoltage = json["data"]["battery_voltage"]["value"].float ?? 0
+ self.status.batteryCapacity = json["data"]["battery_capacity"]["value"].int ?? 0
+ self.status.pvInputPower = json["data"]["pv1_input_power"]["value"].int ?? 0
+
+ case .failure(let error):
+ switch (error) {
+ case .explicitlyCancelled:
+ print("InverterStatusFetcher: request has been canceled")
+ break
+
+ default:
+ self.fetchError = true
+ self.timer?.invalidate()
+ self.timer = nil
+ }
+ }
+
+ self.request = nil
+ }
+ }
+
+ init() {
+ self.fetchError = false
+ self.status = InverterStatus(batteryVoltage: 0, batteryCapacity: 0, activePower: 0, pvInputPower: 0)
+ self.timer = nil
+ self.request = nil
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterStatus.swift b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterStatus.swift
new file mode 100644
index 0000000..cd31eea
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterStatus.swift
@@ -0,0 +1,29 @@
+//
+// InverterStatus.swift
+// InfiniSolar WatchKit Extension
+//
+// Created by Evgeny Zinoviev on 03.08.2021.
+//
+
+import Foundation
+
+struct InverterStatus: Hashable {
+ public var batteryVoltage: Float
+ public var batteryCapacity: Int
+ public var activePower: Int
+ public var pvInputPower: Int
+
+ init(batteryVoltage: Float, batteryCapacity: Int, activePower: Int, pvInputPower: Int) {
+ self.batteryVoltage = batteryVoltage
+ self.batteryCapacity = batteryCapacity
+ self.activePower = activePower
+ self.pvInputPower = pvInputPower
+ }
+
+ func hasData() -> Bool {
+ return self.batteryVoltage != 0
+ || self.batteryCapacity != 0
+ || self.activePower != 0
+ || self.pvInputPower != 0
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterView.swift b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterView.swift
new file mode 100644
index 0000000..779c144
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/InverterView.swift
@@ -0,0 +1,75 @@
+//
+// MainInverterView.swift
+// InfiniSolar WatchKit Extension
+//
+// Created by Evgeny Zinoviev on 08.08.2021.
+//
+
+import SwiftUI
+
+struct InverterView: View {
+ @ObservedObject var state = InverterState()
+ @State var isPresented = false
+
+ var body: some View {
+ VStack(alignment: .leading) {
+ Text("Inverter")
+ .font(.title2)
+ .fontWeight(.thin)
+ Spacer().frame(height: 10)
+
+ // inverter data
+ if self.state.fetchError == true {
+ Text("Error while fetching status.")
+ .multilineTextAlignment(.leading)
+
+ Spacer().frame(height: 10)
+
+ Button(action:{
+ self.state.startFetching()
+ }) {
+ Text("Retry")
+ }
+ // } else if !self.state.status.hasData() {
+ // ProgressView()
+ // .progressViewStyle(CircularProgressViewStyle())
+ } else {
+ Group {
+ Text(String(self.state.status.batteryVoltage) + " V")
+ + Text(" ≈ " + String(self.state.status.batteryCapacity) + " %").fontWeight(.thin)
+
+ Spacer().frame(height: 1)
+
+ Text("Active load is ").fontWeight(.thin)
+ + Text(String(self.state.status.activePower) + " Wh")
+
+ if self.state.status.pvInputPower > 0 {
+ Divider()
+
+ Text("Consuming ").fontWeight(.thin)
+ + Text(String(self.state.status.pvInputPower) + " Wh")
+ + Text(" from panels").fontWeight(.thin)
+ }
+
+ Spacer().frame(height: 15)
+ NavigationLink(destination: GenerationView(), isActive: $isPresented) {
+ Text("Generation stats")
+ .onTapGesture{
+ self.isPresented = true
+ self.state.stopFetching()
+ }
+ }
+ }
+ }
+ }
+ .onAppear() {
+ self.state.startFetching()
+ }
+ }
+}
+
+struct InverterView_Previews: PreviewProvider {
+ static var previews: some View {
+ InverterView()
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/NotificationController.swift b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/NotificationController.swift
new file mode 100644
index 0000000..57c4d8d
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/NotificationController.swift
@@ -0,0 +1,33 @@
+//
+// NotificationController.swift
+// InfiniSolar WatchKit Extension
+//
+// Created by Evgeny Zinoviev on 03.08.2021.
+//
+
+import WatchKit
+import SwiftUI
+import UserNotifications
+
+class NotificationController: WKUserNotificationHostingController<NotificationView> {
+
+ override var body: NotificationView {
+ return NotificationView()
+ }
+
+ override func willActivate() {
+ // This method is called when watch view controller is about to be visible to user
+ super.willActivate()
+ }
+
+ override func didDeactivate() {
+ // This method is called when watch view controller is no longer visible
+ super.didDeactivate()
+ }
+
+ override func didReceive(_ notification: UNNotification) {
+ // This method is called when a notification needs to be presented.
+ // Implement it if you use a dynamic notification interface.
+ // Populate your dynamic notification interface as quickly as possible.
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/NotificationView.swift b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/NotificationView.swift
new file mode 100644
index 0000000..0eb3a2d
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/NotificationView.swift
@@ -0,0 +1,20 @@
+//
+// NotificationView.swift
+// InfiniSolar WatchKit Extension
+//
+// Created by Evgeny Zinoviev on 03.08.2021.
+//
+
+import SwiftUI
+
+struct NotificationView: View {
+ var body: some View {
+ Text("Hello, World!")
+ }
+}
+
+struct NotificationView_Previews: PreviewProvider {
+ static var previews: some View {
+ NotificationView()
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Preview Content/Preview Assets.xcassets/Contents.json b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Preview Content/Preview Assets.xcassets/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/Preview Content/Preview Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/PumpState.swift b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/PumpState.swift
new file mode 100644
index 0000000..4d4e5cc
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/PumpState.swift
@@ -0,0 +1,86 @@
+//
+// PumpState.swift
+// InfiniSolar WatchKit Extension
+//
+// Created by Evgeny Zinoviev on 09.08.2021.
+//
+
+import Alamofire
+import SwiftyJSON
+
+public class PumpState: ObservableObject {
+ @Published var isEnabled: Bool
+ @Published var error: Bool
+ @Published var loading: Bool
+ @Published var setting: Bool
+
+ var request: DataRequest?
+
+ init() {
+ self.loading = true
+ self.error = false
+ self.isEnabled = false
+ self.request = nil
+ self.setting = false
+ }
+
+ func fetch() {
+ self.request = AF.request("http://192.168.5.223:8382/get/").responseJSON { response in
+ self.loading = false
+
+ switch response.result {
+ case .success(let value):
+ let json = JSON(value)
+ self.isEnabled = json["data"].string == "on"
+
+ case .failure(let error):
+ switch (error) {
+ case .explicitlyCancelled:
+ break
+
+ default:
+ print(error)
+ self.error = true
+ }
+ }
+
+// self.loading = false
+ self.request = nil
+ }
+ }
+
+ func setState(on: Bool) {
+ self.setting = true
+ self.request = AF.request("http://192.168.5.223:8382/" + (on ? "on" : "off") + "/").responseJSON { response in
+ self.setting = false
+
+ switch response.result {
+ case .success(_):
+ self.isEnabled = on
+
+ case .failure(let error):
+ switch (error) {
+ case .explicitlyCancelled:
+ break
+
+ default:
+ print(error)
+ self.error = true
+ }
+ }
+
+ self.request = nil
+ }
+ }
+
+ func abort() {
+ if self.request != nil {
+ self.request?.cancel()
+ self.request = nil
+ }
+
+ self.error = false
+ self.loading = true
+ self.isEnabled = false
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/PumpView.swift b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/PumpView.swift
new file mode 100644
index 0000000..270996d
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/PumpView.swift
@@ -0,0 +1,60 @@
+//
+// MainPumpView.swift
+// InfiniSolar WatchKit Extension
+//
+// Created by Evgeny Zinoviev on 09.08.2021.
+//
+
+import SwiftUI
+
+struct PumpView: View {
+ @ObservedObject var state = PumpState()
+
+ var body: some View {
+ VStack(alignment: .leading) {
+ Text("Water pump")
+ .font(.title2)
+ .fontWeight(.thin)
+ Spacer().frame(height: 10)
+
+ if self.state.loading == true {
+ Text("Loading...")
+ .fontWeight(.thin)
+ }
+
+ else if self.state.error == true {
+ Text("Connection error.")
+ }
+
+ else {
+ if self.state.isEnabled == true {
+ Text("The pump is ").fontWeight(.thin)
+ + Text("turned on")
+ Spacer().frame(height: 10)
+ Button(self.state.setting ? "..." : "Turn off") {
+ self.state.setState(on: false)
+ }
+ } else {
+ Text("The pump is ").fontWeight(.thin)
+ + Text("turned off")
+ Spacer().frame(height: 10)
+ Button(self.state.setting ? "..." : "Turn on") {
+ self.state.setState(on: true)
+ }
+ }
+ }
+ }
+ .onAppear() {
+ self.state.fetch()
+ }
+ .onDisappear() {
+ self.state.abort()
+ }
+ }
+}
+
+struct PumpView_Previews: PreviewProvider {
+ static var previews: some View {
+ PumpView()
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/PushNotificationPayload.apns b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/PushNotificationPayload.apns
new file mode 100644
index 0000000..c18b00a
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/PushNotificationPayload.apns
@@ -0,0 +1,20 @@
+{
+ "aps": {
+ "alert": {
+ "body": "Test message",
+ "title": "Optional title",
+ "subtitle": "Optional subtitle"
+ },
+ "category": "myCategory",
+ "thread-id": "5280"
+ },
+
+ "WatchKit Simulator Actions": [
+ {
+ "title": "First Button",
+ "identifier": "firstButtonAction"
+ }
+ ],
+
+ "customKey": "Use this file to define a testing payload for your notifications. The aps dictionary specifies the category, alert text and title. The WatchKit Simulator Actions array can provide info for one or more action buttons in addition to the standard Dismiss button. Any other top level keys are custom payload. If you have multiple such JSON files in your project, you'll be able to select them when choosing to debug the notification interface of your Watch App."
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/RoomState.swift b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/RoomState.swift
new file mode 100644
index 0000000..f387b8b
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/RoomState.swift
@@ -0,0 +1,84 @@
+//
+// RoomState.swift
+// InfiniSolar WatchKit Extension
+//
+// Created by Evgeny Zinoviev on 09.08.2021.
+//
+
+import Alamofire
+import SwiftyJSON
+
+extension Double {
+ /// Rounds the double to decimal places value
+ func rounded(toPlaces places:Int) -> Double {
+ let divisor = pow(10.0, Double(places))
+ return (self * divisor).rounded() / divisor
+ }
+}
+
+
+public class RoomState: ObservableObject {
+ @Published var temp: Double
+ @Published var rh: Double
+ @Published var error: Bool
+
+ var timer: Timer?
+ var request: DataRequest?
+
+ init() {
+ self.error = false
+ self.timer = nil
+ self.request = nil
+
+ self.temp = 0
+ self.rh = 0
+ }
+
+ func start() {
+ if self.timer != nil {
+ self.stop()
+ }
+
+ self.timer = Timer.scheduledTimer(timeInterval: 5,
+ target: self,
+ selector: #selector(fetch),
+ userInfo: nil,
+ repeats: true)
+ self.timer?.fire()
+ }
+
+ func stop() {
+ if self.request != nil {
+ self.request?.cancel()
+ self.request = nil
+ }
+
+ self.error = false
+ self.timer?.invalidate()
+ self.timer = nil
+ }
+
+ @objc func fetch() {
+ self.request = AF.request("http://192.168.5.223:8381/read/").responseJSON { response in
+ self.request = nil
+
+ switch response.result {
+ case .success(let value):
+ let j = JSON(value)
+ self.temp = (j["temp"].double ?? 0).rounded(toPlaces: 2)
+ self.rh = (j["humidity"].double ?? 0).rounded(toPlaces: 2)
+
+ case .failure(let error):
+ switch (error) {
+ case .explicitlyCancelled:
+ break
+
+ default:
+ self.error = true
+ self.timer?.invalidate()
+ self.timer = nil
+ }
+ }
+ }
+ }
+}
diff --git a/watchos/InfiniSolar/InfiniSolar WatchKit Extension/RoomView.swift b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/RoomView.swift
new file mode 100644
index 0000000..8bcf6d7
--- /dev/null
+++ b/watchos/InfiniSolar/InfiniSolar WatchKit Extension/RoomView.swift
@@ -0,0 +1,42 @@
+//
+// MainRoomView.swift
+// InfiniSolar WatchKit Extension
+//
+// Created by Evgeny Zinoviev on 08.08.2021.
+//
+
+import SwiftUI
+
+struct RoomView: View {
+ @ObservedObject var state = RoomState()
+
+ var body: some View {
+ VStack(alignment: .leading) {
+ Text("Room")
+ .font(.title2)
+ .fontWeight(.thin)
+ Spacer().frame(height: 10)
+
+ if self.state.error {
+ Text("Failed to fetch data from si7021d.")
+ }
+
+ else {
+ Text("Temperature is ").fontWeight(.thin) + Text(String(self.state.temp) + " °C")
+ Text("Rel. humidity is ").fontWeight(.thin) + Text(String(self.state.rh) + " %")
+ }
+ }
+ .onAppear() {
+ self.state.start()
+ }
+ .onDisappear() {
+ self.state.stop()
+ }
+ }
+}
+
+struct RoomView_Previews: PreviewProvider {
+ static var previews: some View {
+ RoomView()
+ }
+}