我正在尝试创建一个用于控制WeMo设备的C#应用。我已按照Bernacules here提供的代码示例和说明进行操作。
相关的代码位粘贴在下面。
private void GetAllDevices()
{
var finder = new UPnPDeviceFinder();
var foundDevices = new List<UPnPDevice>();
var deviceType = "upnp:rootdevice";
var devices = finder.FindByType(deviceType, 1);
foreach (UPnPDevice upnpDevice in devices)
{
if (upnpDevice.Type.StartsWith("urn:Belkin:"))
{
....
}
}
}
当我迭代UPnPDeviceFinder找到的设备时,我想出了各种各样的东西,我的媒体服务器,在我的Android手机上运行的一些应用程序,我的Chromecast,但没有WeMos,甚至没有任何东西甚至在贝尔金钟中有贝尔金。
经过一番谷歌搜索后,我发现this article让我弄明白了如何查询&#39; setup.xml&#39;对于每个设备。通过替换&#34; upnp:rootdevice&#34;在上面的代码中,其值来自&lt; DeviceType&gt;在xml中(我相信它是&#34; urn:Belkin:device:controllee:1&#34;),我从UPnPDeviceFinder得到了0个结果。我猜测Belkin最近改变了他们的配置,但是有更多网络笨拙的人能够了解我可以用于什么价值的设备&#39; deviceType&#39;哪个会找到我的WeMos?
答案 0 :(得分:3)
您使用的是哪个版本的Windows?
我的UPnP扫描程序在Windows 7上发现Wemo就好了,但它在Windows 8.1上不起作用
在Windows 8.1上,所有其他UPnP设备都会显示,但Wemo根本没有出现。
答案 1 :(得分:3)
我设法解决了问题。它有点hacky,并没有真正使用upnp协议(因为我无法在Windows 10上完全使用它)。
基本上,我们正在做的是利用netsh命令获取设备列表及其地址。然后我们尝试访问我们知道wemo设备可以运行的不同端口上的setup.xml。当我们得到正确的响应时,它包含所有upnp设备信息,然后我们可以解析我们想要了解的有关设备的任何信息。在这个示例中,我只是进行了简化的解析,只是检查它是否包含单词“Belkin”。它确实有点工作,但是我们应该解析UDN以确定模型,并将friendlyName显示给最终用户。否则,贝尔金制造的其他设备可能会出现。
此方法适用于Windows 10 pc。我没有尝试过其他平台。这是一种强力方法,但所有请求都是异步并行的,所以我们得到的响应很快。无论如何,这是完成所有魔术的课程:
public class WemoScanner
{
public delegate void WemoDeviceFound(WemoDevice device);
public event WemoDeviceFound OnWemoDeviceFound;
public void StartScanning()
{
var addresses = GetAddresses().Where(a => a.Type == "Dynamic");
var tasks = addresses.SelectMany(CheckWemoDevice);
Task.Run(async () => { await Task.WhenAll(tasks).ConfigureAwait(false); });
}
public List<WemoDevice> GetWemoDevices()
{
var devices = new List<WemoDevice>();
OnWemoDeviceFound += device => devices.Add(device);
var addresses = GetAddresses().Where(a => a.Type == "Dynamic");
var tasks = addresses.SelectMany(CheckWemoDevice);
Task.WhenAll(tasks).GetAwaiter().GetResult();
return devices;
}
private NetshResult[] GetAddresses()
{
Process p = new Process();
p.StartInfo.FileName = "netsh.exe";
p.StartInfo.Arguments = "interface ip show ipnet";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
string output = p.StandardOutput.ReadToEnd();
var lines =
output.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries)
.SkipWhile(l => !l.StartsWith("--------"))
.Skip(1);
var results =
lines.Select(l => new NetshResult(l.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)))
.ToArray();
return results;
}
private IEnumerable<Task> CheckWemoDevice(NetshResult netshResult)
{
var tasks = new List<Task>();
for (uint i = 49150; i <= 49156; i++)
{
tasks.Add(CheckWemoDevice(netshResult.IpAddress, i));
}
return tasks;
}
private async Task CheckWemoDevice(string ip, uint port)
{
var url = $"http://{ip}:{port}/setup.xml";
try
{
using (var wc = new WebClient())
{
var resp = await wc.DownloadStringTaskAsync(url);
if (resp.Contains("Belkin")) // TODO: Parse upnp device data and determine device
OnWemoDeviceFound?.Invoke(new WemoDevice {Address = ip, Port = port});
}
}
catch (Exception)
{
}
}
}
以及一些模型类:
public class NetshResult
{
public NetshResult(string[] columns)
{
PhysicalAddress = columns[0];
IpAddress = columns[1];
Type = columns[2];
Interface = columns[3];
}
public string PhysicalAddress { get; private set; }
public string IpAddress { get; private set; }
public string Type { get; private set; }
public string Interface { get; private set; }
}
public class WemoDevice
{
public string Address { get; set; }
public uint Port { get; set; }
}
用法很简单。如果您希望它以异步方式运行(在后台),只需连接到事件OnWemoDeviceFound
并像这样调用StartScanning()
:
var scanner = new WemoScanner();
scanner.OnWemoDeviceFound += device => Console.WriteLine($"{device.Address}:{device.Port}");
scanner.StartScanning();
否则,如果您想要一个同步运行并返回设备列表的方法,只需调用GetWemoDevices()
即可。请注意,这不是真正推荐的,因为在所有“无效”请求发生超时之前它不会返回。如果您希望缩短此时间,可以修改Web请求的超时。
答案 2 :(得分:0)
我知道这是一个非常老的线程,但是我无法在2018年使以上任何解决方案在Windows 10上正常工作。我可以结合使用@Inrego和.NET TcpClient类,检查端口49153是否打开。
public IList<WemoDevice> GetWemoIPs()
{
var wemos = new List<WemoDevice>();
Parallel.For(1, 255, (i) =>
{
var ip = string.Format(this.IpFormat, i);
var device = new WemoDevice(ip);
if (IsWemo(ip))
wemos.Add(device);
});
return wemos;
}
public bool IsWemo(string ipAddress)
{
using (TcpClient tcpClient = new TcpClient())
{
try
{
tcpClient.Connect(ipAddress, 49153);
return true;
}
catch
{
return false;
}
}
}
答案 3 :(得分:-1)
使用属性upnp:rootdevice
,Windows 10上也找不到WeMo。 Inrego你发布了“另一种方式”。其他明智的我正在考虑记录MAC,然后每次做一个ARP来查看IP地址是否已经改变,检查端口49152,49153,49154(据我所知他们可以改变)