Skip to content

YlmzCmlttn

Cemalettin Yılmaz Blog

Menu
  • Home
  • About Me
  • Projects
    • Iot-AR
    • Magnifi-AR
    • Smarthome-IOS
    • Others
  • Categories
    • Articles
    • Augmented Reality
    • Capture The Flag
      • Google CTF
        • 2018
    • Embedded Systems
    • IoT
    • Logisim
    • My Essays
    • Nvidia Jetson
      • Jetson TX1
    • Operating Systems
      • Kali
      • Raspbian
      • Ubuntu
    • Personal
    • Programming
      • Arduino
      • C
      • C#
      • Css
      • Html
      • Js
      • Matlab
      • Node.js
      • Python
      • Swift
      • VHDL
    • Projects
      • Embedded Systems
      • Electric
      • IoT
      • IoT-AR
      • Logisim
      • Magnifi-AR
      • Pose Estimation
    • Raspberry Pi
    • Xilinx
    • Others
Menu

Smart Home Mobile Application | Full Stack

Posted on January 13, 2019 by Yılmaz Cemalettin

Smart Home App

In this project, I made app for practice JSON parsing for IOS application. In this project I made my own backend service with Heroku and Node.js . Backend side is very simple only send random variable for mobile application. You can find all files and videos in here.

Watch app video

Backend | Node.js

I create simple backend (API) for this example SmartHome Application. I use Node.js for developing. This backend send the json for each specific query. You can download full code in here.  This backend don’t have storage system such as MongoDB. I developt this backend for my specific query. Also I deploy this backend on Heroku (http://fathomless-stream-95255.herokuapp.com). You can test with Postman and even you can use this for your example project.

Bellow code shows index.js

Index.js

Index.js
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const express = require('express');
const app = express();
const morgan = require('morgan');
const bodyParser = require('body-parser');
const productRoutes = require('./api/routes/product');
const ordersRoutes = require('./api/routes/orders');
 
const PORT = process.env.PORT || 5000
 
app.use(morgan('dev'));
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.use('/rooms', productRoutes);
app.use('/login', ordersRoutes);
 
app.use((req, res, next) => {
    const error = new Error('Not found');
    error.status = 404;
    next(error);
})
app.use((error, req, res, next) => {
    res.status(error.status || 500);
    res.json({
        error: {
            message: error.message
        }
    });
});
app.listen(PORT, () => console.log(`Listening on ${ PORT }`))

This snippet code shows my login page activity. if user use this routes /login/:username/:password this code works

login
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
router.get('/:username/:password', (req, res, next) => {
    const username = req.params.username;
    const password = req.params.password;
    console.log(username);
    if ((username == "Cemalettin") && (password == "12345") ){
        res.status(200).json({        
            userID: "1",
            rooms: ["livingroom", "bathroom","bedroom","kitchen","garden","saloon","babyroom","balcony"]
        });
    
    }    
    else if ((username == "Mehmet") && (password == "123456") ){
        res.status(200).json({        
            userID: "2",
            rooms: ["garden", "bathroom","bedroom","kitchen","saloon","livingroom","babyroom","balcony"]
        });
    
    }  
    else {
        res.status(200).json({        
            userID: "0"
        });
    }  
});

After that each rooms and sensor variable get with /rooms/:userid/:roomid . Bellow code is not perfect. I don’t prefer to use it. However you can learn concept how to work API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
const express = require('express');
const router = express.Router();
console.log("tesst");
router.get('/:userID', (req, res, next) => {
    const user_id = req.params.userID;
    if (user_id == "1")
    res.status(200).json({
        rooms: ["Livingroom", "Bathroom","Bedroom","Kitchen","Garden","Saloon","Babyroom","Balcony"],
        roomsicon: ["livingroom", "bathroom","bedroom","kitchen","garden","saloon","babyroom","balcony"]
    });
    if (user_id == "2")
    res.status(200).json({
        rooms: ["Garden", "Bathroom","Bedroom","Kitchen","Saloon","Livingroom","Babyroom","Balcony"],
        roomsicon: ["garden", "bathroom","bedroom","kitchen","saloon","livingroom","babyroom","balcony"]
    });
});
 
router.post('/', (req, res, next) => {
    res.status(201).json({
        message: 'Handling Get requests to /products'
    });
});
 
router.get('/:userID/:productId', (req, res, next) =>{
    const room_id = req.params.productId;
    const user_id = req.params.userID;
    if(Math.random() >= 0.5){
        lights = "On"
    }
    else{
        lights = "Off"
    }
    if(Math.random() >= 0.5){
        movement = "Detected"
    }
    else{
        movement = "Not-Detected"
    }
    if(Math.random() >= 0.5){
        gas = "Gas"
    }
    else{
        gas = "Okey"
    }
 
    if(user_id == '1'){
        
        if (room_id === 'Livingroom'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Movement"],
                SensorIcon: ["temperature", "humidity",lights,movement],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,movement]
            });
        }
        else if (room_id === 'Bedroom'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Movement"],
                SensorIcon: ["temperature", "humidity",lights,movement],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,movement]
            });
        }
        else if (room_id === 'Kitchen'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Gas"],
                SensorIcon: ["temperature", "humidity",lights,gas],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,gas]
            });
        }
        else if (room_id === 'Bathroom'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Gas"],
                SensorIcon: ["temperature", "humidity",lights,gas],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,gas]
            });
        }
        else if (room_id === 'Saloon'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Movement"],
                SensorIcon: ["temperature", "humidity",lights,movement],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,movement]
            });
        }
        else if (room_id === 'Babyroom'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Movement"],
                SensorIcon: ["temperature", "humidity",lights,movement],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,movement]
            });
        }
        else if (room_id === 'Garden'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Movement"],
                SensorIcon: ["temperature", "humidity",lights,movement],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,movement]
            });
        }
        else if (room_id === 'Balcony'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Movement"],
                SensorIcon: ["temperature", "humidity",lights,movement],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,movement]
            });
        }  else {
            res.status(200).json({
                message: 'You passed an ID'
            });
        }
 
        
    }
 
    if(user_id == '2'){
        if (room_id === 'Livingroom'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Movement"],
                SensorIcon: ["temperature", "humidity",lights,movement],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,movement]
            });
        }
        else if (room_id === 'Bedroom'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Movement"],
                SensorIcon: ["temperature", "humidity",lights,movement],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,movement]
            });
        }
        else if (room_id === 'Kitchen'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Gas"],
                SensorIcon: ["temperature", "humidity",lights,gas],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,gas]
            });
        }
        else if (room_id === 'Bathroom'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Gas"],
                SensorIcon: ["temperature", "humidity",lights,gas],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,gas]
            });
        }
        else if (room_id === 'Saloon'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Movement"],
                SensorIcon: ["temperature", "humidity",lights,movement],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,movement]
            });
        }
        else if (room_id === 'Babyroom'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Movement"],
                SensorIcon: ["temperature", "humidity",lights,movement],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,movement]
            });
        }
        else if (room_id === 'Garden'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Movement"],
                SensorIcon: ["temperature", "humidity",lights,movement],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,movement]
            });
        }
        else if (room_id === 'Balcony'){
            res.status(200).json({
                SensorNames: ["Temperature", "Humidity","Lights","Movement"],
                SensorIcon: ["temperature", "humidity",lights,movement],
                SensorValues: [parseFloat(Math.random() * (27 - 25) + 25).toPrecision(3), parseFloat(Math.random() * (60 - 50) + 50).toPrecision(3),lights,movement]
            });
        }  else {
            res.status(200).json({
                message: 'You passed an ID'
            });
        }
 
        
    }
 
 
    
});
 
router.patch('/:productId', (req, res, next) => {
    res.status(200).json({
        message: 'Updated'
    });
});
 
router.delete('/:productId', (req, res, next) => {
    res.status(200).json({
        message: 'Deleted product'
    });
});
 
module.exports = router;

 

Ios Mobile App | Swift

Bellow picture shows the main storyboard. Application have 3 page which are, login, rooms and roomsdetails pages.

Firstly I created models

userModel.swift

Swift
1
2
3
4
import Foundation
struct userModel : Codable {
    let userID : String
}

roomModel.swift

Swift
1
2
3
4
5
import Foundation
struct roomModel : Decodable {
    let rooms : [String]
    let roomsicon : [String]
}

sensorsModel.swift

Swift
1
2
3
4
5
6
import Foundation
struct sensorsModel : Decodable {
    let SensorNames : [String]
    let SensorValues : [String]
    let SensorIcon : [String]
}

currentUser.swift

I create this model for hold the current user in phone memory. I mean, when user close application and start to application again application regonize the current user and doesn’t want to login again.

Swift
1
2
3
4
import Foundation
struct userModel : Codable {
    let userID : String
}

webService.swift

Swift
1
2
3
4
import Foundation
struct webService{
    static var baseURL = "http://fathomless-stream-95255.herokuapp.com"
}

After that I create ViewControllers codes.

LoginViewController.swift

Swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//
//  ViewController.swift
//  smartHome
//
//  Created by Cemalettin Yılmaz on 10.12.2018.
//  Copyright © 2018 Cemalettin Yılmaz. All rights reserved.
//
 
import UIKit
import MaterialComponents.MaterialTextFields
import MaterialComponents.MaterialButtons
//extension ViewController: WebServiceDelegate{
//    func login(Username: String, Password: String) -> userModel {
//        userID = userModel.i
//    }
//}
class LoginViewController: UIViewController {
 
    @IBOutlet weak var warningLabel: UILabel!
    @IBOutlet weak var LoginButton: MDCButton!
    @IBOutlet weak var Username: MDCTextField!
    @IBOutlet weak var Password: MDCTextField!
    public var usernameTextFieldController: MDCTextInputControllerOutlined!
    public var passwordTextFieldController: MDCTextInputControllerOutlined!
    var userID : String?
 
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        Username.text = nil
        Password.text = nil
        warningLabel.text = nil
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        hideKeyboardOnTap()
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
        Username.placeholder = "Username"
        Password.placeholder = "Password"
        usernameTextFieldController = MDCTextInputControllerOutlined.init(textInput: Username)
        usernameTextFieldController.isFloatingEnabled = true
        passwordTextFieldController = MDCTextInputControllerOutlined.init(textInput: Password)
        passwordTextFieldController.isFloatingEnabled = true
        Username.autocorrectionType = .no
        Password.autocorrectionType = .no
        LoginButton.layer.cornerRadius = 10
    }
 
    
    @IBAction func loginPressed(_ sender: Any) {
        guard let name = Username.text else {
            warningLabel.text = "Invalid username or password"
            return}
        guard let pass = Password.text else {
            warningLabel.text = "Invalid username or password"
            return}
        if name.count == 0 {
            warningLabel.text = "Invalid username or password"
            return}
        if pass.count == 0 {
            warningLabel.text = "Invalid username or password"
            return}
        let sv = UIViewController.displaySpinner(onView: self.view)
        
        //        let loggedUser = ws?.login(Username: name, Password: pass)
        let baseURL = webService.baseURL
        let targetURL = "\(baseURL)/login/\(name)/\(pass)"
        let target = URL(string: targetURL)
        
        guard let url = target else {return}
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            DispatchQueue.main.async {
                let decoder = JSONDecoder()
                let user = try! decoder.decode(userModel.self, from: data!)
                if user.userID != "0" {
                    currentUser.userID = user.userID
                    self.performSegue(withIdentifier: "login", sender: nil)
                } else {
                    UIViewController.removeSpinner(spinner: sv)
                    self.warningLabel.text = "Invalid username or password"
                    
                }
            }
        }
        task.resume()
    }
  
    public func hideKeyboardOnTap() {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.hideKeyboard))
        tap.cancelsTouchesInView = false
        view.addGestureRecognizer(tap)
    }
    @objc public func hideKeyboard() {
        view.endEditing(true)
    }
    @objc func keyboardWillShow(notification: NSNotification) {
        if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
            if self.view.frame.origin.y == 0 {
                self.view.frame.origin.y -= keyboardSize.height
            }
        }
    }
    
    @objc func keyboardWillHide(notification: NSNotification) {
        if self.view.frame.origin.y != 0 {
            self.view.frame.origin.y = 0
        }
    }
    
}
 
extension UIViewController {
    class func displaySpinner(onView : UIView) -> UIView {
        let spinnerView = UIView.init(frame: onView.bounds)
        spinnerView.backgroundColor = UIColor.init(red: 0.5, green: 0.5, blue: 0.5, alpha: 0.5)
        let ai = UIActivityIndicatorView.init(style: .whiteLarge)
        ai.startAnimating()
        ai.center = spinnerView.center
        
        DispatchQueue.main.async {
            spinnerView.addSubview(ai)
            onView.addSubview(spinnerView)
        }
        
        return spinnerView
    }
    
    class func removeSpinner(spinner :UIView) {
        DispatchQueue.main.async {
            spinner.removeFromSuperview()
        }
    }
}

RoomsViewController.swift

Swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//
//  MyCollectionViewController.swift
//  tableViewExample
//
//  Created by Cemalettin Yılmaz on 10.12.2018.
//  Copyright © 2018 Cemalettin Yilmaz. All rights reserved.
//
 
import UIKit
 
extension RoomsViewController : UIScrollViewDelegate {
    
    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        
        if Int(targetContentOffset.pointee.y)%collectionCellHeight > collectionCellHeight/2 {
            targetContentOffset.pointee.y = CGFloat(collectionCellHeight*(Int(targetContentOffset.pointee.y)/collectionCellHeight + 1))
        } else {
            targetContentOffset.pointee.y = CGFloat(collectionCellHeight*(Int(targetContentOffset.pointee.y)/collectionCellHeight))
        }
    }
    
}
extension RoomsViewController : UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return rooms.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let myCell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCollectionCell", for: indexPath) as! RoomCollectionViewCell
        
        myCell.nameLabel.text = rooms[indexPath.row]
        myCell.collectionViewCellImage.image = UIImage(named: roomsicon[indexPath.row])
        myCell.layer.cornerRadius = 10
        return myCell
    }
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let screenWidth = self.view.frame.size.width
        let screenHeight = self.view.frame.size.height
        
        return CGSize(width: screenWidth/2 - 30, height: screenHeight/3)
    }
    
    
}
class RoomsViewController: UIViewController {
    var collectionCellHeight = 100
 
    @IBOutlet weak var myCollectionView: UICollectionView!
    var rooms : [String] = []
    var roomsicon : [String] = []
    override func viewDidLoad() {
        super.viewDidLoad()
        getRoomNames(userID: currentUser.userID)
        collectionCellHeight = Int(view.frame.size.height/3 + 5)
 
        
    }
 
    func getRoomNames(userID : String){
        let baseURL = webService.baseURL
        let targetURL = "\(baseURL)/rooms/\(userID)"
        let target = URL(string: targetURL)
        
        guard let url = target else {return}
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            DispatchQueue.main.async {
                let decoder = JSONDecoder()
                let myRoomModel = try! decoder.decode(roomModel.self, from: data!)
                self.rooms = myRoomModel.rooms
                self.roomsicon = myRoomModel.roomsicon
                self.myCollectionView.reloadData()
            }
        }
        task.resume()
    }
    
    @IBAction func logoutButtonPressed(_ sender: Any) {
        currentUser.userID = "0"
        let documentsDirectory =
            FileManager.default.urls(for: .documentDirectory,
                                     in: .userDomainMask).first!
        let archiveURL =
            documentsDirectory.appendingPathComponent("userID")
                .appendingPathExtension("plist")
        let propertyListEncoder = PropertyListEncoder()
        var ucs = userModel(userID: "0")
        let encodedNote = try? propertyListEncoder.encode(ucs)
        try? encodedNote?.write(to: archiveURL, options: .noFileProtection)
        
        self.performSegue(withIdentifier: "logout", sender: nil)
        
        
    }
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
        guard segue.identifier == "toRoomDetail" else {return}
        let cell = sender as! RoomCollectionViewCell
        let indexPath = myCollectionView.indexPath(for: cell)
        let selectedRoom = rooms[indexPath!.row]
        let detailViewController = segue.destination as! RoomDetailViewController
        detailViewController.currentRoom = selectedRoom
    }
}

RoomDetailViewController.swift

Swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//
//  PostDetailViewController.swift
//  smartHome
//
//  Created by Cemalettin Yılmaz on 10.12.2018.
//  Copyright © 2018 Cemalettin Yılmaz. All rights reserved.
//
 
import UIKit
 
extension RoomDetailViewController : UIScrollViewDelegate {
    
    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        
        
        
        if Int(targetContentOffset.pointee.y)%tableViewCellRowHeight > tableViewCellRowHeight/2 {
            targetContentOffset.pointee.y = CGFloat(tableViewCellRowHeight*(Int(targetContentOffset.pointee.y)/tableViewCellRowHeight + 1))
        } else {
            targetContentOffset.pointee.y = CGFloat(tableViewCellRowHeight*(Int(targetContentOffset.pointee.y)/tableViewCellRowHeight))
        }
    }
    
}
extension RoomDetailViewController : UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        return mySensors?.SensorNames.count ?? 0
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let myCell = tableView.dequeueReusableCell(withIdentifier: "sensorCell") as! SensorTableViewCell
        
        myCell.sensorName.text = mySensors?.SensorNames[indexPath.row]
        myCell.sensorValue.text = mySensors?.SensorValues[indexPath.row]
        myCell.sensorImage.image = UIImage(named: (mySensors?.SensorIcon[indexPath.row])!)
      
        return myCell
    }
    
    
    
    //    func tableV
    
}
class RoomDetailViewController: UIViewController {
    @IBOutlet weak var myTableView: UITableView!
    var mySensors : sensorsModel?
    var currentRoom : String?
    var tableViewCellRowHeight = 150
 
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.title = currentRoom
        getSensors(roomName: currentRoom!, userID: currentUser.userID)
        // Do any additional setup after loading the view.
    }
    func getSensors(roomName : String , userID : String){
        let baseURL = webService.baseURL
        let targetURL = "\(baseURL)/rooms/\(userID)/\(roomName)"
        let target = URL(string: targetURL)
        guard let url = target else {return}
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            DispatchQueue.main.async {
                let decoder = JSONDecoder()
                self.mySensors = try! decoder.decode(sensorsModel.self, from: data!)
                self.myTableView.reloadData()
 
            }
        }
        task.resume()
        
    }
}

After that I create collection controllers

RoomCollectionViewCell.swift

Swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//
//  RoomCollectionViewCell.swift
//  smartHome
//
//  Created by Cemalettin Yılmaz on 10.12.2018.
//  Copyright © 2018 Cemalettin Yılmaz. All rights reserved.
//
 
import UIKit
 
class RoomCollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var collectionViewCellImage: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
 
    
    override func awakeFromNib() {
        super.awakeFromNib()
        collectionViewCellImage.layer.cornerRadius = 20
        // Initialization code
    }
}

SensorTableViewCell.swift

Swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//
//  SensorTableViewCell.swift
//  smartHome
//
//  Created by Cemalettin Yılmaz on 10.12.2018.
//  Copyright © 2018 Cemalettin Yılmaz. All rights reserved.
//
 
import UIKit
 
class SensorTableViewCell: UITableViewCell {
 
    @IBOutlet weak var sensorImage: UIImageView!
    @IBOutlet weak var sensorName: UILabel!
    @IBOutlet weak var sensorValue: UILabel!
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }
 
    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
 
        // Configure the view for the selected state
    }
 
}

Also I added in Delegate code for saving current user id.

AppDelegate.swift

 

Swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//
//  AppDelegate.swift
//  smartHome
//
//  Created by Cemalettin Yılmaz on 10.12.2018.
//  Copyright © 2018 Cemalettin Yılmaz. All rights reserved.
//
 
import UIKit
 
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
 
    var window: UIWindow?
 
 
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        let propertyListDecoder = PropertyListDecoder()
        let documentsDirectory =
            FileManager.default.urls(for: .documentDirectory,
                                     in: .userDomainMask).first!
        let archiveURL =
            documentsDirectory.appendingPathComponent("userID")
                .appendingPathExtension("plist")
        if let retrievedNoteData = try? Data(contentsOf: archiveURL),let decodedNote = try? propertyListDecoder.decode(userModel.self,from: retrievedNoteData) {
            if decodedNote.userID == "0" {
                return true
            } else {
                let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
                currentUser.userID = decodedNote.userID
                self.window!.rootViewController = storyboard.instantiateViewController(withIdentifier: "navController")
            }
        }
        return true
    }
 
    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }
 
    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }
 
    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }
 
    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }
 
    func applicationWillTerminate(_ application: UIApplication) {
        let documentsDirectory =
            FileManager.default.urls(for: .documentDirectory,
                                     in: .userDomainMask).first!
        let archiveURL =
            documentsDirectory.appendingPathComponent("userID")
                .appendingPathExtension("plist")
        let propertyListEncoder = PropertyListEncoder()
        var current = userModel(userID: currentUser.userID)
        let encodedNote = try? propertyListEncoder.encode(current)
        try? encodedNote?.write(to: archiveURL, options: .noFileProtection)
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }
 
 
}

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

My Motto

“Learn to share, Share to learn”

LinkedIn Badge

Cemalettin Yılmaz

Ads

Archives

Categories

  • Articles (1)
  • Augmented Reality (3)
  • Capture The Flag (23)
    • Google CTF (22)
      • 2018 (13)
      • 2019 (9)
    • PicoCTF (1)
      • 2019 (1)
  • Embedded Systems (3)
  • IoT (3)
  • Logisim (1)
  • My Essays (3)
  • Nvidia Jetson (5)
    • Xavier (5)
  • Operating Systems (24)
    • Kali (3)
    • Raspbian (2)
    • Ubuntu (21)
  • Others (1)
  • Personal (1)
  • Programming (44)
    • Arduino (4)
    • C (10)
    • C# (4)
    • C++ (5)
    • Css (1)
    • CUDA (6)
    • Html (1)
    • Js (2)
    • Libraries (5)
      • OpenCV (3)
      • OpenGL (2)
    • Matlab (14)
    • Node.js (5)
    • Python (6)
    • Swift (3)
  • Programs (4)
    • Tools (4)
  • Projects (21)
    • Books Solutions (8)
    • Electric (2)
    • Embedded Systems (2)
    • Energy Harvesting (1)
    • IoT (2)
    • IoT-AR (1)
    • Logisim (1)
    • Magnifi-AR (3)
    • Pose Estimation (3)
    • Smarthome-Ios (1)
  • Raspberry Pi (3)
  • Uncategorized (2)
  • YZlib (1)

Recent Posts

  • atof stof stod problems with local floating point separator in C/C++
  • Pico CTF 2019 Answers
  • YZlib: Personal C++ Library
  • Drive to target | Google CTF 2019
  • FriendSpaceBookPlusAllAccessRedPremium | Google CTF 2019

Recent Comments

  • AbaShelha on Ghidra Installation on Ubuntu |18.04, 16.04, 14.04
  • Peter on Ghidra Installation on Ubuntu |18.04, 16.04, 14.04
  • Yılmaz Cemalettin on Ghidra Installation on Ubuntu |18.04, 16.04, 14.04
  • Yılmaz Cemalettin on 16-Bit CPU on Logisim
  • Jenny on 16-Bit CPU on Logisim
  • MOON on 16-Bit CPU on Logisim
  • anti on Ghidra Installation on Ubuntu |18.04, 16.04, 14.04
  • hunkerjr on STOP GAN | Google CTF 2019
  • Shaq on 16-Bit CPU on Logisim
  • NURUL AFIQAH MOHD HASBULLAH on 16-Bit CPU on Logisim

Linkedln

© 2022 YlmzCmlttn | Powered by Superbs Personal Blog theme