Let user type in device name to read variable

If a user want to read a variable from a device, is there any way of letting the user type in (via UITextfield) the device name of that device? So far I only get this error message "Cannot assign value of type ‘SparkDevice?’ to type ‘String’.

How are you trying to do this? Are you creating an iOS app of your own? What code are you using now that gives you that error message?

Here is the specific code:

var myPhoton : SparkDevice?
var myDeviceName = ""

@IBOutlet weak var deviceName: UILabel!
@IBOutlet weak var myDeviceNameTF: UITextField!
    
    @IBAction func confirmMyDeviceNameTF(_ sender: Any) {
        
        
        myDeviceName = myDeviceNameTF.text!
        
        if myDeviceNameTF.text == "" {
            
            deviceName.text = "Please type in your device name below"
            
        } else {
            
            deviceAdded()
            
            myDeviceName = myPhoton
            
            myPhoton?.getVariable("temperature", completion: { (result:AnyObject?, error:NSError?) -> Void in
                if let e=error {
                    println("Failed reading temperature from device")
                }
                else {
                    if let temp = result as? Float {
                        println("Room temperature is \(temp) degrees")
                    }
                }
            })
            
            
        }
        
    }

This line is the problem. You can’t set myDeviceName which is a string, equal to myPhoton which is a SparkDevice. You still need to use code similar to what you posted in a previous thread to get the device based on its name,

SparkCloud.sharedInstance().getDevices { (sparkDevices:[AnyObject]?, error:NSError?) -> Void in
            if error != nil {
                print("Check your internet connectivity")
            }
            else {
                if let devices = sparkDevices as? [SparkDevice] {
                    print(sparkDevices)
                    for device in devices {
                        if device.name == myDeviceName { // here is where you use the name entered by the user to get the device
                            self.myPhoton = device
                        }
                    }
                }
            }
        }

This code could be placed inside the text field delegate method, textFieldDidEndEditing, so it will be executed when you finish editing the text field.

Disregarding the ‘how’, isn’t it better to present the user with a list of the devices he has access to and have him/her pick one of those, rather than requiring him to enter the specific name?

2 Likes

Thanks for the help Ric, it works!

@Moors7 Do you have any ways of doing that in an simple way, I’d appreciate it!

I would do this using a UITableView to present the names to the user. Something like this to get the names into the table view,

var deviceArray: [SparkDevice]!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        SparkCloud.sharedInstance().getDevices { (sparkDevices:[Any]?, error:Error?) -> Void in
            if error != nil {
                print("Check your internet connectivity")
            }
            else {
                if let devices = sparkDevices as? [SparkDevice] {
                    self.deviceArray = devices
                    self.tableView.reloadData()
                }
            }
        }
    }

Fill the table with the names of the devices in the deviceArray, and set myPhoton equal to the device the user picks by clicking on one row of the table view.

1 Like

It’s what the Particle app does, it gets all devices and lets you select the one you want to do stuff with. Might want to take a look at how they did it, I personally haven’t got any experience with developing native apps.

@Ric Am I doing something wrong here because I’m not getting anything in my table view?

    import UIKit

class tableViewViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    var deviceArray: [SparkDevice]!
    
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        SparkCloud.sharedInstance().getDevices { (sparkDevices:[Any]?, error:Error?) -> Void in
            if error != nil {
                print("Check your internet connectivity")
            }
            else {
                if let devices = sparkDevices as? [SparkDevice] {
                    self.deviceArray = devices
                    self.tableView.reloadData()
                }
            }
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
      
    }
    
    public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        return 1
        
    }
    
    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "Cell")
        
        return cell
        
    }

}

You’re missing anything in cellForRowAtIndexPath that does anything with the cell. You need to put the data into the cell’s textLabel. Also, when you return the numberOfRows, you need to check if the array is nil first (because the call to get the devices is asynchronous), and if not, return the count of the array. Something like this,

var deviceArray: [SparkDevice]!
var myPhoton: SparkDevice!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        SparkCloud.sharedInstance().getDevices { (sparkDevices:[AnyObject]?, error:NSError?) -> Void in
            if error != nil {
                print("Check your internet connectivity")
            }else {
                if let devices = sparkDevices as? [SparkDevice] {
                    self.deviceArray = devices
                    self.tableView.relaodData()
                }
            }
        }
    }

   
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let numRows = deviceArray != nil ? deviceArray.count : 0
        return numRows
    }
    
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        let dev = deviceArray[indexPath.row]
        cell.textLabel!.text = dev.name
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        myPhoton = deviceArray[indexPath.row]
    }

Be sure to give the cell in the storyboard, the identifier “cell”

Thanks again for the support @Ric!