Skip to content

Commit

Permalink
Add UI for temperature sensor in CHIPTool iOS app (project-chip#3250)
Browse files Browse the repository at this point in the history
* Add UI screen to controll temeprature sensor from iOS app

* Add reporting setup code

* Call CHIPTemperatureMeasurement callback methods

* Add dismiss keyboard and some logs

* Restyled by whitespace

* Restyled by clang-format

Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
2 people authored and austinh0 committed Feb 3, 2021
1 parent 52ae672 commit 4724fb1
Show file tree
Hide file tree
Showing 5 changed files with 277 additions and 2 deletions.
14 changes: 14 additions & 0 deletions src/darwin/CHIPTool/CHIPTool.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
B243A6692513A73600E56FEA /* RootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B243A6682513A73600E56FEA /* RootViewController.m */; };
B2946A4224C99D53005C87D0 /* WifiViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B2946A4124C99D53005C87D0 /* WifiViewController.m */; };
B2946A9B24C9A7BF005C87D0 /* DefaultsUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B2946A9A24C9A7BF005C87D0 /* DefaultsUtils.m */; };
B2F51E99252DCDC000911FA5 /* TemperatureSensorViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B2F51E98252DCDC000911FA5 /* TemperatureSensorViewController.m */; };
B2F53AEB245B0D140010745E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B2F53AE9245B0D140010745E /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -74,6 +75,8 @@
B2946A4124C99D53005C87D0 /* WifiViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WifiViewController.m; sourceTree = "<group>"; };
B2946A9924C9A7BF005C87D0 /* DefaultsUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DefaultsUtils.h; sourceTree = "<group>"; };
B2946A9A24C9A7BF005C87D0 /* DefaultsUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DefaultsUtils.m; sourceTree = "<group>"; };
B2F51E97252DCDC000911FA5 /* TemperatureSensorViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TemperatureSensorViewController.h; sourceTree = "<group>"; };
B2F51E98252DCDC000911FA5 /* TemperatureSensorViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TemperatureSensorViewController.m; sourceTree = "<group>"; };
B2F53AEA245B0D140010745E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = UI/Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -191,6 +194,7 @@
B204A623244E1D0600C7C0E1 /* SceneDelegate.m */,
B243A6672513A73600E56FEA /* RootViewController.h */,
B243A6682513A73600E56FEA /* RootViewController.m */,
B2F51E93252DCC9E00911FA5 /* Temperature Sensor */,
B2946A3F24C99D21005C87D0 /* Wifi */,
0C79937824858B3B0047A373 /* QRCode */,
0C79937924858B4F0047A373 /* Echo client */,
Expand All @@ -217,6 +221,15 @@
path = Wifi;
sourceTree = "<group>";
};
B2F51E93252DCC9E00911FA5 /* Temperature Sensor */ = {
isa = PBXGroup;
children = (
B2F51E97252DCDC000911FA5 /* TemperatureSensorViewController.h */,
B2F51E98252DCDC000911FA5 /* TemperatureSensorViewController.m */,
);
path = "Temperature Sensor";
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -322,6 +335,7 @@
B2946A9B24C9A7BF005C87D0 /* DefaultsUtils.m in Sources */,
991DC091247747F500C13860 /* EchoViewController.m in Sources */,
B204A621244E1D0600C7C0E1 /* AppDelegate.m in Sources */,
B2F51E99252DCDC000911FA5 /* TemperatureSensorViewController.m in Sources */,
B243A6692513A73600E56FEA /* RootViewController.m in Sources */,
B204A632244E1D0700C7C0E1 /* main.m in Sources */,
B204A624244E1D0600C7C0E1 /* SceneDelegate.m in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion src/darwin/CHIPTool/CHIPTool/UI Helpers/CHIPUIViewUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ + (UILabel *)addTitle:(NSString *)title toView:(UIView *)view

titleLabel.translatesAutoresizingMaskIntoConstraints = false;
[titleLabel.centerXAnchor constraintEqualToAnchor:view.centerXAnchor].active = YES;
[titleLabel.topAnchor constraintEqualToAnchor:view.topAnchor constant:100].active = YES;
[titleLabel.topAnchor constraintEqualToAnchor:view.topAnchor constant:110].active = YES;

return titleLabel;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#import "EchoViewController.h"
#import "OnOffViewController.h"
#import "QRCodeViewController.h"
#import "TemperatureSensorViewController.h"
#import "WifiViewController.h"

@implementation RootViewController
Expand All @@ -36,7 +37,7 @@ - (void)setUpTableView
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:self.tableView];
self.options = @[ @"QRCode scanner", @"Echo client", @"Light on / off cluster", @"Wifi Configuration" ];
self.options = @[ @"QRCode scanner", @"Echo client", @"Light on / off cluster", @"Temperature Sensor", @"Wifi Configuration" ];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
Expand Down Expand Up @@ -71,13 +72,22 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
[self pushLightOnOffCluster];
break;
case 3:
[self pushTemperatureSensor];
break;
case 4:
[self pushNetworkConfiguration];
break;
default:
break;
}
}

- (void)pushTemperatureSensor
{
TemperatureSensorViewController * controller = [TemperatureSensorViewController new];
[self.navigationController pushViewController:controller animated:YES];
}

- (void)pushNetworkConfiguration
{
WifiViewController * controller = [WifiViewController new];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// TemperatureSensorViewController.h
// CHIPTool
//
// Created by Shana Azria on 07/10/2020.
// Copyright © 2020 CHIP. All rights reserved.
//

#import <CHIP/CHIP.h>
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface TemperatureSensorViewController : UIViewController <CHIPDeviceControllerDelegate>

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
//
// TemperatureSensorViewController.m
// CHIPTool
//
// Created by Shana Azria on 07/10/2020.
// Copyright © 2020 CHIP. All rights reserved.
//

#import "TemperatureSensorViewController.h"
#import "CHIPUIViewUtils.h"
#import "DefaultsUtils.h"
#import <CHIP/CHIP.h>

@interface TemperatureSensorViewController ()
@property (nonatomic, strong) UILabel * temperatureLabel;
@property (nonatomic, strong) UITextField * minIntervalInSecondsTextField;
@property (nonatomic, strong) UITextField * maxIntervalInSecondsTextField;
@property (nonatomic, strong) UITextField * deltaInFahrenheitTextField;
@property (nonatomic, strong) UIButton * sendReportingSetup;

@property (nonatomic, strong) CHIPTemperatureMeasurement * chipTempMeasurement;
@property (readwrite) CHIPDevice * chipDevice;
@property (readwrite) CHIPDeviceController * chipController;

@end

@implementation TemperatureSensorViewController

// MARK: UIViewController methods

- (void)viewDidLoad
{
[super viewDidLoad];
[self setupUI];

UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];

// initialize the device controller
dispatch_queue_t callbackQueue = dispatch_queue_create("com.zigbee.chip.tempsensorvc.callback", DISPATCH_QUEUE_SERIAL);
self.chipController = [CHIPDeviceController sharedController];
[self.chipController setDelegate:self queue:callbackQueue];

uint64_t deviceID = CHIPGetNextAvailableDeviceID();
if (deviceID > 1) {
// Let's use the last device that was paired
deviceID--;
NSError * error;
self.chipDevice = [self.chipController getPairedDevice:deviceID error:&error];
self.chipTempMeasurement = [[CHIPTemperatureMeasurement alloc] initWithDevice:self.chipDevice
endpoint:1
queue:callbackQueue];
}

[self readCurrentTemperature];
}

- (IBAction)sendReportingSetup:(id)sender
{
NSLog(@"Status: User request to send reporting setup.");
[self reportFromUserEnteredSettings];
}

- (IBAction)refreshTemperatureMeasurement:(id)sender
{
NSLog(@"Status: User request to refresh temperature reading.");
[self readCurrentTemperature];
}

// MARK: UI helpers

- (void)dismissKeyboard
{
[_minIntervalInSecondsTextField resignFirstResponder];
[_maxIntervalInSecondsTextField resignFirstResponder];
[_deltaInFahrenheitTextField resignFirstResponder];
}

- (void)setupUI
{
self.view.backgroundColor = UIColor.whiteColor;

// Title
UILabel * titleLabel = [CHIPUIViewUtils addTitle:@"Temperature Sensor" toView:self.view];

// stack view
UIStackView * stackView = [UIStackView new];
stackView.axis = UILayoutConstraintAxisVertical;
stackView.distribution = UIStackViewDistributionFill;
stackView.alignment = UIStackViewAlignmentLeading;
stackView.spacing = 30;
[self.view addSubview:stackView];

stackView.translatesAutoresizingMaskIntoConstraints = false;
[stackView.topAnchor constraintEqualToAnchor:titleLabel.bottomAnchor constant:40].active = YES;
[stackView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:30].active = YES;
[stackView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-30].active = YES;

// Temperature label
_temperatureLabel = [UILabel new];
_temperatureLabel.text = @"°F";
_temperatureLabel.textColor = UIColor.blackColor;
_temperatureLabel.textAlignment = NSTextAlignmentCenter;
_temperatureLabel.font = [UIFont systemFontOfSize:50 weight:UIFontWeightThin];
[stackView addArrangedSubview:_temperatureLabel];
_temperatureLabel.translatesAutoresizingMaskIntoConstraints = false;
[_temperatureLabel.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor].active = YES;

// Reporting settings
UILabel * reportingLabel = [UILabel new];
reportingLabel.text = @"Reporting Setup";
reportingLabel.textColor = UIColor.blackColor;
reportingLabel.textAlignment = NSTextAlignmentLeft;
reportingLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold];
[stackView addArrangedSubview:reportingLabel];

reportingLabel.translatesAutoresizingMaskIntoConstraints = false;
[reportingLabel.centerXAnchor constraintEqualToAnchor:stackView.centerXAnchor].active = YES;

// Min interval in seconds
_minIntervalInSecondsTextField = [UITextField new];
_minIntervalInSecondsTextField.keyboardType = UIKeyboardTypeNumberPad;
UILabel * minIntervalInSecondsLabel = [UILabel new];
[minIntervalInSecondsLabel setText:@"Min. interval (sec):"];
UIView * minIntervalInSecondsView = [CHIPUIViewUtils viewWithLabel:minIntervalInSecondsLabel
textField:_minIntervalInSecondsTextField];
[stackView addArrangedSubview:minIntervalInSecondsView];

minIntervalInSecondsView.translatesAutoresizingMaskIntoConstraints = false;
[minIntervalInSecondsView.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor].active = YES;

// Min interval in seconds
_maxIntervalInSecondsTextField = [UITextField new];
_maxIntervalInSecondsTextField.keyboardType = UIKeyboardTypeNumberPad;
UILabel * maxIntervalInSecondsLabel = [UILabel new];
[maxIntervalInSecondsLabel setText:@"Max. interval (sec):"];
UIView * maxIntervalInSecondsView = [CHIPUIViewUtils viewWithLabel:maxIntervalInSecondsLabel
textField:_maxIntervalInSecondsTextField];
[stackView addArrangedSubview:maxIntervalInSecondsView];

maxIntervalInSecondsView.translatesAutoresizingMaskIntoConstraints = false;
[maxIntervalInSecondsView.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor].active = YES;

// Delta
_deltaInFahrenheitTextField = [UITextField new];
_deltaInFahrenheitTextField.keyboardType = UIKeyboardTypeNumberPad;
UILabel * deltaInFahrenheitLabel = [UILabel new];
[deltaInFahrenheitLabel setText:@"Delta (F):"];
UIView * deltaInFahrenheitView = [CHIPUIViewUtils viewWithLabel:deltaInFahrenheitLabel textField:_deltaInFahrenheitTextField];
[stackView addArrangedSubview:deltaInFahrenheitView];

deltaInFahrenheitView.translatesAutoresizingMaskIntoConstraints = false;
[deltaInFahrenheitView.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor].active = YES;

// Reporting button
_sendReportingSetup = [UIButton new];
[_sendReportingSetup setTitle:@"Send reporting settings" forState:UIControlStateNormal];
[_sendReportingSetup addTarget:self action:@selector(sendReportingSetup:) forControlEvents:UIControlEventTouchUpInside];
_sendReportingSetup.backgroundColor = UIColor.systemBlueColor;
_sendReportingSetup.titleLabel.font = [UIFont systemFontOfSize:17];
_sendReportingSetup.titleLabel.textColor = [UIColor whiteColor];
_sendReportingSetup.layer.cornerRadius = 5;
_sendReportingSetup.clipsToBounds = YES;
[stackView addArrangedSubview:_sendReportingSetup];

_sendReportingSetup.translatesAutoresizingMaskIntoConstraints = false;
[_sendReportingSetup.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor].active = YES;

// Refresh button
UIBarButtonItem * button = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
target:self
action:@selector(refreshTemperatureMeasurement:)];
self.navigationItem.rightBarButtonItem = button;
}

- (void)updateTempInUI:(int)newTemp
{
_temperatureLabel.text = [NSString stringWithFormat:@"%@ °F", @(newTemp)];
NSLog(@"Status: Updated temp in UI to %@", _temperatureLabel.text);
}

// MARK: CHIPTemperatureMeasurement

- (void)readCurrentTemperature
{
CHIPDeviceCallback completionHandler = ^(NSError * error) {
NSLog(@"Status: Read temperature request completed with error %@", [error description]);
};

[self.chipTempMeasurement readAttributeMeasuredValue:completionHandler];
}

- (void)reportFromUserEnteredSettings
{
CHIPDeviceCallback onCompletionCallback = ^(NSError * error) {
NSLog(@"Status: update reportAttributeMeasuredValue completed with error %@", [error description]);
};

CHIPDeviceCallback onChangeCallback = ^(NSError * error) {
NSLog(@"Status: Temp value changed with error %@", [error description]);
};
int minIntervalSeconds = [_minIntervalInSecondsTextField.text intValue] * 1000;
int maxIntervalSeconds = [_maxIntervalInSecondsTextField.text intValue] * 1000;
int deltaInFahrenheit = [_deltaInFahrenheitTextField.text intValue];

NSLog(@"Sending temp reporting values: min %@ max %@ value %@", @(minIntervalSeconds), @(maxIntervalSeconds),
@(deltaInFahrenheit));

[self.chipTempMeasurement reportAttributeMeasuredValue:onCompletionCallback
onChange:onChangeCallback
minInterval:minIntervalSeconds
maxInterval:maxIntervalSeconds
change:deltaInFahrenheit];
}

// MARK: CHIPDeviceControllerDelegate
- (void)deviceControllerOnConnected
{
NSLog(@"Status: Device connected");
}

- (void)deviceControllerOnError:(nonnull NSError *)error
{
NSLog(@"Status: Device Controller error %@", [error description]);
}

- (void)deviceControllerOnMessage:(nonnull NSData *)message
{
NSLog(@"Status: Received a message.");
// TODO: Use callback APIs to show read response
}

@end

0 comments on commit 4724fb1

Please sign in to comment.