move watchos app sources here (which should be rewritten anyway, and usable only in very specific conditions)
This commit is contained in:
parent
d549f428cb
commit
bb32e56ca2
3
.gitignore
vendored
3
.gitignore
vendored
@ -21,3 +21,6 @@ CMakeListsPrivate.txt
|
||||
/localwebsite/config.local.php
|
||||
/localwebsite/cache
|
||||
/localwebsite/test.php
|
||||
|
||||
/watchos/InfiniSolar/Pods
|
||||
xcuserdata
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"role" : "notificationCenter",
|
||||
"scale" : "2x",
|
||||
"size" : "24x24",
|
||||
"subtype" : "38mm"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"role" : "notificationCenter",
|
||||
"scale" : "2x",
|
||||
"size" : "27.5x27.5",
|
||||
"subtype" : "42mm"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"role" : "companionSettings",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"role" : "companionSettings",
|
||||
"scale" : "3x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"role" : "appLauncher",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40",
|
||||
"subtype" : "38mm"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"role" : "appLauncher",
|
||||
"scale" : "2x",
|
||||
"size" : "44x44",
|
||||
"subtype" : "40mm"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"role" : "appLauncher",
|
||||
"scale" : "2x",
|
||||
"size" : "50x50",
|
||||
"subtype" : "44mm"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"role" : "quickLook",
|
||||
"scale" : "2x",
|
||||
"size" : "86x86",
|
||||
"subtype" : "38mm"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"role" : "quickLook",
|
||||
"scale" : "2x",
|
||||
"size" : "98x98",
|
||||
"subtype" : "42mm"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"role" : "quickLook",
|
||||
"scale" : "2x",
|
||||
"size" : "108x108",
|
||||
"subtype" : "44mm"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch-marketing",
|
||||
"scale" : "1x",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
31
watchos/InfiniSolar/InfiniSolar WatchKit App/Info.plist
Normal file
31
watchos/InfiniSolar/InfiniSolar WatchKit App/Info.plist
Normal file
@ -0,0 +1,31 @@
|
||||
<?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 App</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>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
</array>
|
||||
<key>WKWatchKitApp</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"screen-width" : ">161"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"screen-width" : ">183"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"screen-width" : ">161"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"screen-width" : ">183"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"screen-width" : ">161"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"screen-width" : ">183"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"screen-width" : ">161"
|
||||
},
|
||||
{
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"screen-width" : ">183"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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()
|
||||
// }
|
||||
//}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
@ -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>
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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.
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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."
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
1046
watchos/InfiniSolar/InfiniSolar.xcodeproj/project.pbxproj
Normal file
1046
watchos/InfiniSolar/InfiniSolar.xcodeproj/project.pbxproj
Normal file
File diff suppressed because it is too large
Load Diff
7
watchos/InfiniSolar/InfiniSolar.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
watchos/InfiniSolar/InfiniSolar.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
@ -0,0 +1,8 @@
|
||||
<?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>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
10
watchos/InfiniSolar/InfiniSolar.xcworkspace/contents.xcworkspacedata
generated
Normal file
10
watchos/InfiniSolar/InfiniSolar.xcworkspace/contents.xcworkspacedata
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:InfiniSolar.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
@ -0,0 +1,8 @@
|
||||
<?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>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
@ -0,0 +1,8 @@
|
||||
<?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>PreviewsEnabled</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
33
watchos/InfiniSolar/InfiniSolarTests/InfiniSolarTests.swift
Normal file
33
watchos/InfiniSolar/InfiniSolarTests/InfiniSolarTests.swift
Normal file
@ -0,0 +1,33 @@
|
||||
//
|
||||
// InfiniSolarTests.swift
|
||||
// InfiniSolarTests
|
||||
//
|
||||
// Created by Evgeny Zinoviev on 03.08.2021.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import InfiniSolar_WatchKit_Extension
|
||||
|
||||
class InfiniSolarTests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testExample() throws {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
}
|
||||
|
||||
func testPerformanceExample() throws {
|
||||
// This is an example of a performance test case.
|
||||
self.measure {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
22
watchos/InfiniSolar/InfiniSolarTests/Info.plist
Normal file
22
watchos/InfiniSolar/InfiniSolarTests/Info.plist
Normal file
@ -0,0 +1,22 @@
|
||||
<?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>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>
|
||||
</dict>
|
||||
</plist>
|
@ -0,0 +1,42 @@
|
||||
//
|
||||
// InfiniSolarUITests.swift
|
||||
// InfiniSolarUITests
|
||||
//
|
||||
// Created by Evgeny Zinoviev on 03.08.2021.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class InfiniSolarUITests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
// In UI tests it is usually best to stop immediately when a failure occurs.
|
||||
continueAfterFailure = false
|
||||
|
||||
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testExample() throws {
|
||||
// UI tests must launch the application that they test.
|
||||
let app = XCUIApplication()
|
||||
app.launch()
|
||||
|
||||
// Use recording to get started writing UI tests.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
}
|
||||
|
||||
func testLaunchPerformance() throws {
|
||||
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
|
||||
// This measures how long it takes to launch your application.
|
||||
measure(metrics: [XCTApplicationLaunchMetric()]) {
|
||||
XCUIApplication().launch()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
watchos/InfiniSolar/InfiniSolarUITests/Info.plist
Normal file
22
watchos/InfiniSolar/InfiniSolarUITests/Info.plist
Normal file
@ -0,0 +1,22 @@
|
||||
<?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>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>
|
||||
</dict>
|
||||
</plist>
|
37
watchos/InfiniSolar/Podfile
Normal file
37
watchos/InfiniSolar/Podfile
Normal file
@ -0,0 +1,37 @@
|
||||
# Uncomment the next line to define a global platform for your project
|
||||
# platform :ios, '9.0'
|
||||
|
||||
target 'InfiniSolar' do
|
||||
# Comment the next line if you don't want to use dynamic frameworks
|
||||
#use_frameworks!
|
||||
|
||||
# Pods for InfiniSolar
|
||||
|
||||
target 'InfiniSolarTests' do
|
||||
inherit! :search_paths
|
||||
# Pods for testing
|
||||
end
|
||||
|
||||
target 'InfiniSolarUITests' do
|
||||
# Pods for testing
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
target 'InfiniSolar WatchKit App' do
|
||||
# Comment the next line if you don't want to use dynamic frameworks
|
||||
#use_frameworks!
|
||||
|
||||
# Pods for InfiniSolar WatchKit App
|
||||
|
||||
end
|
||||
|
||||
target 'InfiniSolar WatchKit Extension' do
|
||||
# Comment the next line if you don't want to use dynamic frameworks
|
||||
#use_frameworks!
|
||||
|
||||
# Pods for InfiniSolar WatchKit Extension
|
||||
pod 'Alamofire', '~> 5.1'
|
||||
pod 'SwiftyJSON', '~> 4.0'
|
||||
pod 'SwiftSocket'
|
||||
end
|
20
watchos/InfiniSolar/Podfile.lock
Normal file
20
watchos/InfiniSolar/Podfile.lock
Normal file
@ -0,0 +1,20 @@
|
||||
PODS:
|
||||
- Alamofire (5.4.3)
|
||||
- SwiftyJSON (4.3.0)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Alamofire (~> 5.1)
|
||||
- SwiftyJSON (~> 4.0)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- Alamofire
|
||||
- SwiftyJSON
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: e447a2774a40c996748296fa2c55112fdbbc42f9
|
||||
SwiftyJSON: 6faa0040f8b59dead0ee07436cbf76b73c08fd08
|
||||
|
||||
PODFILE CHECKSUM: 4af73cac3a538d18238200492e84f50cb3fe8db3
|
||||
|
||||
COCOAPODS: 1.10.2
|
Loading…
x
Reference in New Issue
Block a user