Skip to content
This repository has been archived by the owner on Apr 18, 2018. It is now read-only.

Commit

Permalink
Flow meter on status page.
Browse files Browse the repository at this point in the history
  • Loading branch information
John Boiles committed Oct 14, 2010
1 parent eca49bb commit 10611ae
Show file tree
Hide file tree
Showing 20 changed files with 1,017 additions and 20 deletions.
Binary file modified KegBoard/board/kegboard.sch
Binary file not shown.
1 change: 0 additions & 1 deletion KegPad/Classes/Controllers/KBDisplayViewController.h
Expand Up @@ -28,7 +28,6 @@
#import "KBUserView.h"
#import "KBChalkLabel.h"


@class KBApplicationDelegate;

/*!
Expand Down
4 changes: 4 additions & 0 deletions KegPad/Classes/Controllers/KBStatusViewController.h
Expand Up @@ -24,6 +24,7 @@
#import "KBKegTemperature.h"
#import "KBChartView.h"
#import "KBLeaderboardView.h"
#import "KBFlowIndicator.h"

@class KBApplicationDelegate;

Expand All @@ -45,6 +46,8 @@
KBChartView *chartView_;

KBLeaderboardView *leaderboardView_;

KBFlowIndicator *flowIndicator_;

KBApplicationDelegate *delegate_; // weak
}
Expand All @@ -60,6 +63,7 @@
@property (nonatomic, retain) IBOutlet UILabel *totalPouredAmountLabel;
@property (nonatomic, retain) IBOutlet KBChartView *chartView;
@property (nonatomic, retain) IBOutlet KBLeaderboardView *leaderboardView;
@property (nonatomic, retain) IBOutlet KBFlowIndicator *flowIndicator;
@property (nonatomic, assign) KBApplicationDelegate *delegate;


Expand Down
17 changes: 14 additions & 3 deletions KegPad/Classes/Controllers/KBStatusViewController.m
Expand Up @@ -34,10 +34,20 @@ @implementation KBStatusViewController
lastPourAmountLabel=lastPourAmountLabel_, lastPourAmountUnitsLabel=lastPourAmountUnitsLabel_,
percentRemaingLabel=percentRemaingLabel_, totalPouredAmountLabel=totalPouredAmountLabel_,
temperatureLabel=temperatureLabel_, temperatureDescriptionLabel=temperatureDescriptionLabel_,
chartView=chartView_, leaderboardView=leaderboardView_, delegate=delegate_;
chartView=chartView_, leaderboardView=leaderboardView_, delegate=delegate_, flowIndicator=flowIndicator_;

- (id)init {
if ((self = [super initWithNibName:nil bundle:nil])) { }
if ((self = [super initWithNibName:nil bundle:nil])) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"KBFlowIndicator" owner:nil options:nil];
for (id currentObject in topLevelObjects) {
if ([currentObject isKindOfClass:[KBFlowIndicator class]]) {
self.flowIndicator = currentObject;
break;
}
}
self.flowIndicator.frame = CGRectMake(20, 331, 402, 350);
[self.view addSubview:self.flowIndicator];
}
return self;
}

Expand All @@ -54,6 +64,7 @@ - (void)dealloc {
[temperatureDescriptionLabel_ release];
[chartView_ release];
[leaderboardView_ release];
[flowIndicator_ release];
[super dealloc];
}

Expand Down Expand Up @@ -86,7 +97,7 @@ - (void)updateKeg:(KBKeg *)keg {
percentRemaingLabel_.text = @"";
totalPouredAmountLabel_.text = @"-";
}
}
}

- (void)setLastKegPour:(KBKegPour *)kegPour {
self.view;
Expand Down
4 changes: 4 additions & 0 deletions KegPad/Classes/Data/KBKegManager.m
Expand Up @@ -155,4 +155,8 @@ - (void)kegProcessing:(KBKegProcessing *)kegProcessing didReceiveRFIDTagId:(NSSt
}
}

- (void)kegProcessing:(KBKegProcessing *)kegProcessing didUpdatePourWithAmount:(double)amount flowRate:(double)flowRate {
[[NSNotificationCenter defaultCenter] postNotificationName:KBUpdatePourNotification object:kegProcessing];
}

@end
4 changes: 3 additions & 1 deletion KegPad/Classes/KBNotifications.h
Expand Up @@ -38,4 +38,6 @@ extern NSString *const KBUnknownTagIdNotification; // With tag id (NSString), if

extern NSString *const KBDidSelectUserNotification; // With user (KBUser)

extern NSString *const KBActivityNotification; // If there is an user activity
extern NSString *const KBActivityNotification; // If there is an user activity

extern NSString *const KBUpdatePourNotification; // For when an active pour is updated
4 changes: 3 additions & 1 deletion KegPad/Classes/KBNotifications.m
Expand Up @@ -39,4 +39,6 @@
NSString *const KBUnknownTagIdNotification = @"KBUnknownTagIdNotification";
NSString *const KBDidSelectUserNotification = @"KBDidSelectUserNotification";

NSString *const KBActivityNotification = @"KBActivityNotification";
NSString *const KBActivityNotification = @"KBActivityNotification";

NSString *const KBUpdatePourNotification = @"KBUpdatePourNotification";
8 changes: 3 additions & 5 deletions KegPad/Classes/Processing/KBKegProcessing.h
Expand Up @@ -21,7 +21,6 @@

#import "KBKegboard.h"

#define KB_TEMPERATURE_DIFFERENCE_THRESHOLD 0.1
#define KB_VOLUME_DIFFERENCE_THRESHOLD 0.001
// Adjust this value based on the flow meter properties
#define KB_VOLUME_PER_TICK 0.0001639344262
Expand All @@ -35,16 +34,14 @@
- (void)kegProcessing:(KBKegProcessing *)kegProcessing didChangeTemperature:(double)temperature;
- (void)kegProcessing:(KBKegProcessing *)kegProcessing didReceiveRFIDTagId:(NSString *)tagID;
//- (void)kegProcessing:(KBKegProcessing *)kegProcessing didError:(KBError *)error;
- (void)kegProcessing:(KBKegProcessing *)kegProcessing didUpdatePourWithAmount:(double)amount flowRate:(double)flowRate;
@end


@interface KBKegProcessing : NSObject <KBKegboardDelegate> {
id<KBKegProcessingDelegate> _delegate;

KBKegboard *_kegboard;

double _temperatureDifference;


double _flowRate; // in litres / second

double _lastVolume;
Expand All @@ -58,5 +55,6 @@

@property (assign, nonatomic) id<KBKegProcessingDelegate> delegate;
@property (readonly, nonatomic) double flowRate;
@property (readonly, nonatomic) double pourVolume;

@end
12 changes: 6 additions & 6 deletions KegPad/Classes/Processing/KBKegProcessing.m
Expand Up @@ -48,6 +48,10 @@ - (void)endPour {
}
}

- (double)pourVolume {
return _lastVolume - _pourStartVolume;
}

#pragma mark Delegates (KBKegboard)

- (void)kegboard:(KBKegboard *)kegboard didReceiveHello:(KBKegboardMessageHello *)message {
Expand Down Expand Up @@ -83,15 +87,11 @@ - (void)kegboard:(KBKegboard *)kegboard didReceiveMeterStatus:(KBKegboardMessage
}
}
_lastVolume = volume;
[self.delegate kegProcessing:self didUpdatePourWithAmount:(volume - _pourStartVolume) flowRate:_flowRate];
}

- (void)kegboard:(KBKegboard *)kegboard didReceiveTemperatureReading:(KBKegboardMessageTemperatureReading *)message {
// If difference since last message send is significant, notify delegate
double temperature = [message sensorReading];
if (abs(temperature - _temperatureDifference) > KB_TEMPERATURE_DIFFERENCE_THRESHOLD) {
[self.delegate kegProcessing:self didChangeTemperature:temperature];
_temperatureDifference = temperature;
}
[self.delegate kegProcessing:self didChangeTemperature:[message sensorReading]];
}

- (void)kegboard:(KBKegboard *)kegboard didReceiveOutputStatus:(KBKegboardMessageOutputStatus *)message { }
Expand Down
6 changes: 3 additions & 3 deletions KegPad/Classes/Processing/KBKegboard.m
Expand Up @@ -106,7 +106,7 @@ - (void)readLoop {
while (headerPosition < KBSP_PREFIX_LENGTH) {
char byte;
sleeperRead(gFileDescriptor, &byte, 1);
calculatedCRC = crc_update(calculatedCRC, &byte, 1);
calculatedCRC = crc_update(calculatedCRC, (unsigned char *)&byte, 1);
// Byte was expected
if (byte == KBSP_PREFIX[headerPosition]) {
headerPosition += 1;
Expand All @@ -127,7 +127,7 @@ - (void)readLoop {

// Read message type and message length
sleeperRead(gFileDescriptor, headerBytes, 4);
calculatedCRC = crc_update(calculatedCRC, headerBytes, 4);
calculatedCRC = crc_update(calculatedCRC, (unsigned char *)headerBytes, 4);
NSInteger messageId = [KBKegboardMessage parseUInt16:headerBytes];
NSInteger messageLength = [KBKegboardMessage parseUInt16:&headerBytes[2]];
if (messageLength > KBSP_PAYLOAD_MAXLEN) {
Expand All @@ -137,7 +137,7 @@ - (void)readLoop {

// Read payload and trailer
sleeperRead(gFileDescriptor, payload, messageLength);
calculatedCRC = crc_update(calculatedCRC, payload, messageLength);
calculatedCRC = crc_update(calculatedCRC, (unsigned char *)payload, messageLength);
sleeperRead(gFileDescriptor, crc, 2);
sleeperRead(gFileDescriptor, trailer, 2);

Expand Down
52 changes: 52 additions & 0 deletions KegPad/Classes/Views/KBFlowIndicator.h
@@ -0,0 +1,52 @@
//
// KBFlowIndicator.h
//
// Created by John Boiles on 10/13/10.
// Copyright 2010 Yelp. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

@interface KBFlowIndicator : UIView {
UIImageView *needleView_;
UIImageView *fillView_;
UILabel *volumeLabel_;
UILabel *flowLabel_;

double _minimumFlowRate;
double _maximumFlowRate;
double _minimumAngle;
double _maximumAngle;
double _flowRate;

double _minimumVolume;
double _maximumVolume;
double _minimumTopY;
double _maximumTopY;
double _volume;

NSTimer *_simulationTimer;
BOOL _simulatedValueIncreasing;
}

@property (nonatomic, retain) IBOutlet UIImageView *needleView;
@property (nonatomic, retain) IBOutlet UIImageView *fillView;
@property (nonatomic, retain) IBOutlet UILabel *volumeLabel;
@property (nonatomic, retain) IBOutlet UILabel *flowLabel;

- (void)setFlowRate:(double)flowRate animated:(BOOL)animated;

- (void)setVolume:(double)volume animated:(BOOL)animated;

@end
131 changes: 131 additions & 0 deletions KegPad/Classes/Views/KBFlowIndicator.m
@@ -0,0 +1,131 @@
//
// KBFlowIndicator.m
//
// Created by John Boiles on 10/13/10.
// Copyright 2010 Yelp. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

#import "KBFlowIndicator.h"
#import "KBKegProcessing.h"
#import "KBNotifications.h"
#import "KBTypes.h"

@implementation KBFlowIndicator

@synthesize needleView=needleView_, fillView=fillView_, volumeLabel=volumeLabel_, flowLabel=flowLabel_;

- (void)awakeFromNib {
_minimumFlowRate = 0;
_maximumFlowRate = 1;
_minimumAngle = -0.41 * M_PI;
_maximumAngle = 0.41 * M_PI;
_flowRate = 0;

_minimumVolume = 0;
_maximumVolume = 16;
_minimumTopY = 306;
_maximumTopY = 210;
_volume = 0;

[self setFlowRate:0 animated:NO];
[self setVolume:0 animated:NO];
//[self simulateValues];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_onUpdatePourNotification:) name:KBUpdatePourNotification object:nil];
}

- (void)setRotationRadians:(CGFloat)radians animated:(BOOL)animated {
if (animated) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDuration:0.1];
[UIView setAnimationBeginsFromCurrentState:YES];
CGAffineTransform transform = CGAffineTransformRotate(CGAffineTransformIdentity, radians);
needleView_.transform = CGAffineTransformTranslate(transform, 0, -71);
[UIView commitAnimations];
} else {
CGAffineTransform transform = CGAffineTransformRotate(CGAffineTransformIdentity, radians);
needleView_.transform = CGAffineTransformTranslate(transform, 0, -71);
[needleView_ setNeedsDisplay];
}
}

- (void)setFlowRate:(double)flowRate animated:(BOOL)animated {
[flowLabel_ setText:[NSString stringWithFormat:@"%0.1f", flowRate]];
if (flowRate > _maximumFlowRate) flowRate = _maximumFlowRate;
if (flowRate < _minimumFlowRate) flowRate = _minimumFlowRate;
_flowRate = flowRate;
double fraction = (flowRate - _minimumFlowRate) / (_maximumFlowRate - _minimumFlowRate);
double angle = fraction * (_maximumAngle - _minimumAngle) + _minimumAngle;
[[self gh_proxyOnMainThread] setRotationRadians:angle animated:animated];
}

- (void)setTopY:(CGFloat)topY animated:(BOOL)animated {
if (animated) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDuration:0.1];
[UIView setAnimationBeginsFromCurrentState:YES];
fillView_.frame = CGRectMake(fillView_.frame.origin.x, topY, fillView_.frame.size.width, fillView_.frame.size.height);
[UIView commitAnimations];
} else {
fillView_.frame = CGRectMake(fillView_.frame.origin.x, topY, fillView_.frame.size.width, fillView_.frame.size.height);
[fillView_ setNeedsDisplay];
}
}

- (void)setVolume:(double)volume animated:(BOOL)animated {
[volumeLabel_ setText:[NSString stringWithFormat:@"%0.1f", volume]];
if (volume > _maximumVolume) volume = _maximumVolume;
if (volume < _minimumVolume) volume = _minimumVolume;
_volume = volume;
double fraction = (volume - _minimumVolume) / (_maximumVolume - _minimumVolume);
CGFloat topY = fraction * (_maximumTopY - _minimumTopY) + _minimumTopY;
[[self gh_proxyOnMainThread] setTopY:topY animated:animated];
}

- (void)simulateValues {
_simulationTimer = [[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(setSimulatedValue) userInfo:nil repeats:YES] retain];
_simulatedValueIncreasing = YES;
}

- (void)setSimulatedValue {
double interval = (_maximumFlowRate - _minimumFlowRate) / 20;
double interval2 = (_maximumVolume - _minimumVolume) / 20;
if (_simulatedValueIncreasing) {
_flowRate += interval;
_volume += interval2;
if (_flowRate > _maximumFlowRate) {
_simulatedValueIncreasing = NO;
}
} else {
_flowRate -= interval;
_volume -= interval2;
if (_flowRate < _minimumFlowRate) {
_simulatedValueIncreasing = YES;
}
}
[self setVolume:_volume animated:YES];
[self setFlowRate:_flowRate animated:YES];
}

- (void)_onUpdatePourNotification:(NSNotification *)notification {
KBKegProcessing *kegProcessing = (KBKegProcessing *)[notification object];
[self setVolume:kegProcessing.pourVolume * kLitersToOunces animated:YES];
[self setFlowRate:kegProcessing.flowRate * kLitersToOunces animated:YES];
}

@end

1 comment on commit 10611ae

@ipatch
Copy link

@ipatch ipatch commented on 10611ae Mar 23, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im going to try and get this flow reading working in KegCop very soon :)

Please sign in to comment.