먹는게 남는거다!

미박스용 USB 전원 케이블

잡다...

거실 멀티탭에 TV, IPTV 셋탑, 미박스 등 이것저것 연결했더니 문어발이 되었습니다.

어떻게든 어답터를 줄여볼려고 고민하던 중 찾아낸 USB 케이블입니다.

USB 멀티 충전기에 연결하니 딱 맞습니다.

 

구매처: http://mhemall.co.kr/front/php/product.php?product_no=333

Home Assistant + 무선 공유기(ASUS RT-AC68U)로 재실, 외출 표시하기

장난감

 

Home Assistant에서는 휴대폰 같이 우리가 항상 휴대하는 물건으로 재실, 외출 등을 판단해야 합니다.

아래 링크를 클릭하면 Home Assistant를 지원하는 여러 센서를 확인할 수 있는데 저는 ASUS RT-AC68U 무선 공유기를 사용하기 때문에 이 중에서 Asuswrt와 Bluetooth Tracker를 이용해서 해당 센서가 휴대폰을 인지하면 집에 있는 것으로 판단하도록 Home Assistant를 구축하였습니다.

 

Netgear, DD-WRT, LINKSYS, OpenWRT, Tomato, Xiaomi Router 등 다양한 공유기를 지원하기 때문에 본인이 사용하는 공유기를 선택하시면 됩니다.

 

https://www.home-assistant.io/integrations#presence-detection

 

Integrations

List of the built-in integrations of Home Assistant.

www.home-assistant.io

 

1. Asuswrt 설정

 

1) Asus 공유기 SSH 설정

먼저 Home Assistant가 ASUS 공유기에 접속하여 현재 공유기에 연결된 기기들의 정보를 가져올 수 있도록 공유기 설정 페이지에 들어가서 SSH를 허용해야 합니다.

참고: https://lightinglife.tistory.com/144

 

[ASUS 공유기 tvheadend 설치 #1] 아수스 공유기 SSH 외부 접속 활성화 및 JFFS 파티션 활성화

아수스 공유기에 내장된, 관리자 모드에서 지원하는 기능인 다운로드 마스터를 이용하여 토렌트를 다운받는 방법에 대해 알아봤습니다. 실제로 여기까지만 포스팅할려고 했는데, 다운로드 마스터가 조금 느리고,..

lightinglife.tistory.com

 

2) Asuswrt 설정 (https://www.home-assistant.io/integrations/asuswrt/)

Home Assistant 설정 파일인 configuration.yaml 에 아래 내용을 추가합니다.

asuswrt:
  host: 192.168.0.1    # 사용하시는 공유기 IP를 입력하세요.
  username: admin    # 사용하시는 공유기 접속 ID를 입력하세요.
  password: dfsg234    # 사용하시는 공유기 접속 비밀번호를 입력하세요.
  protocol: ssh
  port: 22 
  sensors: []

 

3) Device Tracker 설정 (https://www.home-assistant.io/integrations/device_tracker/)

Configuration.yaml 에 아래와 같이 Device Tracker를 설정합니다.

device_tracker:
  - platform: asuswrt
    host: 192.168.0.1    # 사용하시는 공유기 IP를 입력하세요.
    interval_seconds: 10
    consider_home: 120
    new_device_defaults:
      track_new_devices: false
      hide_if_away: false

 

위와 같이 설정 후 Home Assistant를 재시작하면 configuration.yaml 파일이 있는 폴더에 known_devices.yaml 라는 파일이 생깁니다.

이 파일은 Device Tracker가 인지한 기기들 목록으로 이 중에서 본인의 핸드폰 정보라고 생각되는 항목의 track을 false에서 true로 변경하면 됩니다.

galaxy_s10:
  hide_if_away: true
  icon:
  mac: 42:28:A8:70:BC:YC   # 기기마다 다릅니다.
  name: Galaxy-S10   # 휴대폰 기종마다 다릅니다.
  picture:
  track: true

 

2. Bluetooth 설정

 

Asuswrt 설정만으로는 부족한 부분이 있습니다.

Android의 절전 정책으로 간혹 Wifi가 꺼져서 외출로 변경되는 일이 발생하기 때문입니다.

이를 보완하기 위해서 Bluetooth로 이중 확인을 하는 것이 좋습니다.

 

1) Bluetooth 페어링(Pairing)

Bluetooth 설정을 하기에 앞서 휴대폰과 Home Assistant가 설치된 기기에 대해 Bluetooth 페어링을 해야 합니다.

이 부분은 Home Assistant가 설치된 기기마다 다르기 때문에 구글에서 찾아봐야 합니다.

 

2) Bluetooth Tracker 설정 (https://www.home-assistant.io/integrations/bluetooth_tracker/)

Bluetooth 설정은 간단합니다.  Asuswrt 설정 시 추가했던 device_tracker에 아래와 같이 bluetooth_tracker만 추가하면 됩니다.

device_tracker:
  - platform: asuswrt
    host: 192.168.0.1    # 사용하시는 공유기 IP를 입력하세요.
    interval_seconds: 10
    consider_home: 120
    new_device_defaults:
      track_new_devices: false
      hide_if_away: false
  - platform: bluetooth_tracker     

 

Home Assistant 를 재시작하면 아래와 같이 known_devices.yaml 파일에 휴대폰 bluetooth 정보가 추가됩니다. (Mac address에서 알 수 있듯이 Bluetooth인 경우 Mac address가 BT_ 으로 시작합니다.)

이 역시 track를 false에서 true로 변경해야 합니다.

galaxy_s10_2:
  hide_if_away: false
  icon:
  mac: BT_A8:2Y:BZ:D8:1F:0J    # 기기마다 다릅니다.
  name: Galaxy S10    # 휴대폰 기종마다 다릅니다.
  picture:
  track: true

 

마지막으로 Home Assistant를 한번 더 재시작하고 Home Assistant에 접속 후 설정 > 구성원 메뉴를 클릭합니다.

구성원 페이지에서 이름을 클릭 후 위와 같은 팝업이 뜨면 known_devices.yaml에서 찾아낸 휴대폰을 추적 대상 기기에 설정합니다. 

 

 

Home Assistant + Docker + Raspberry Pi 설치

장난감

Home Assistant 설치에 앞서 Docker가 설치되어 있지 않을 경우 Docker를 설치하셔야 합니다.

 

1. Home Assistant 설치

Home Assistant를 설치하는 여러 방법이 있지만 Docker를 이용할 경우 root 계정으로 작업하는 것이 편합니다.

su

 

아래의 명령어로 Home Assistant를 설치합니다.

/home/pi/homeassistant 는 Home Assistant 설정 폴더 경로로 원하시는 경로를 입력하시면 되고

Asia/Seoul 는 Time Zone입니다. (https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)

이 역시 원하시는 시간대로 정하시면 됩니다.

docker run --init -d --name="home-assistant" -e "TZ=Asia/Seoul" -v /home/pi/homeassistant:/config --net=host homeassistant/raspberrypi3-homeassistant:stable

 

참고: https://www.home-assistant.io/docs/installation/docker/

 

Installation on Docker

Instructions to install Home Assistant on a Docker.

www.home-assistant.io

 

2. HTTPS 통신을 위한 SSL 인증서 설치

Let's Encrypt 설치를 다룬 글이 많이 있지만 아래 블로그 포스트를 따라하는 것이 가장 확실합니다.

천천히 따라하면 30분도 걸리지 않을 정도로 간단합니다.

 

참고: https://www.splitbrain.org/blog/2017-08/10-homeassistant_duckdns_letsencrypt

 

HASS, DuckDNS and Let's Encrypt [splitbrain.org]

2 years ago I blogged about… When you want to make a local HomeAssistant (a home automation software I mentioned before) available from the Internet, you probably want to secure it with SSL. There's an official tutorial on how to do that, but it has a few

www.splitbrain.org

한가지 주의할 점은 우리는 본문과 달리 Docker에 Home Assistant를 설치한 상황이라 Home Assistant가 인식하는 본인의 절대 경로가 다르다는 것입니다.

때문에 Reconfigure HomeAssistant 섹션에서 언급한 pem 파일들의 경로를 본문과 달리 아래와 같이 설정해야 합니다.

 

[ fullchain. pem ]

변경 전: /home/homeassistant/dehydrated/certs/myhome.duckdns.org/fullchain.pem

변경 후: ./dehydrated/certs/myhome.duckdns.org/fullchain.pem

 

[ privkey.pem ]

변경 전: /home/homeassistant/dehydrated/certs/myhome.duckdns.org/privkey.pem

변경 후: ./dehydrated/certs/myhome.duckdns.org/privkey.pem

 

3. Tip

1) UPNP 안 보이기

discovery:
  ignore:
    - igd   

 

 

 

ASP.NET Request QueryString encoding

C#, ASP.NET
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
private System.Collections.Generic.Dictionary<stringstring> requestDic;
 
protected void Page_Load(object sender, EventArgs e)
{
    ParseRequestQueryStringData(System.Text.Encoding.GetEncoding(949));
 
    string t = GetRequestQueryString("strErrMsg");
    lbMessage.Text = t;
}
 
private void ParseRequestQueryStringData(System.Text.Encoding encoding)
{
    string url = HttpUtility.UrlDecode(Request.RawUrl, encoding);
    int s = url.IndexOf('?'0);
    if (s < 0)
    {
        return;
    }
 
    requestDic = new System.Collections.Generic.Dictionary<stringstring>();
    string requestData = "&" + url.Substring(s + 1+ "&";
 
    int pos = requestData.IndexOf('&'0);
    int pos2 = 0;
 
    string paramName;
    string paramValue;
 
    while (pos >= 0 && pos2 >= 0)
    {
        pos2 = requestData.IndexOf('=', pos);
 
        if (pos2 > 0)
        {
            paramName = requestData.Substring(pos + 1, pos2 - pos - 1);
 
            pos = requestData.IndexOf('&', pos2);
 
            if (pos > 0)
            {
                paramValue = requestData.Substring(pos2 + 1, pos - pos2 - 1);
                requestDic.Add(paramName, paramValue);
            }
        }
    }
}
 
private string GetRequestQueryString(string paramName)
{
    try
    {
        return requestDic[paramName];
    }
    catch (System.Collections.Generic.KeyNotFoundException keyEx)
    {
        return null;
    }
}
cs

 

ASP.NET Request Form encoding

C#, ASP.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private static Dictionary<stringstring> GetEncodedForm(System.IO.Stream stream, System.Text.Encoding encoding)
{
    System.IO.StreamReader reader = new System.IO.StreamReader(stream, System.Text.Encoding.ASCII);
    return GetEncodedForm(reader.ReadToEnd(), encoding);
}
 
private static Dictionary<stringstring> GetEncodedForm(string urlEncoded, System.Text.Encoding encoding)
{
    Dictionary<stringstring> form = new Dictionary<stringstring>();
    string[] pairs = urlEncoded.Split("&".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
 
    foreach (string pair in pairs)
    {
        string[] pairItems = pair.Split("=".ToCharArray(), 2, StringSplitOptions.RemoveEmptyEntries);
        string name = HttpUtility.UrlDecode(pairItems[0], encoding);
        string value = (pairItems.Length > 1) ? HttpUtility.UrlDecode(pairItems[1], encoding) : null;
        form.Add(name, value);
    }
    return form;
}
cs

 

출처: https://stackoverflow.com/questions/1012120/iso-8859-1-to-utf8-in-asp-net-2

[C#] EPPlus로 엑셀 생성 시 필요없는 property 제거하기

C#, ASP.NET

EPPlus를 이용하여 POCO 클래스를 excel 파일에 출력할 때

Attribute를 이용하여 특정 property를 제외하는 방법



Attribute


1
public class EpplusIgnore : Attribute { }
cs



Epplus extensions


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static class Extensions
{
    public static ExcelRangeBase LoadFromCollectionFiltered<T>(this ExcelRangeBase @this, IEnumerable<T> collection) 
where T:class
    {
        MemberInfo[] membersToInclude = typeof(T)
            .GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(p=>!Attribute.IsDefined(p,typeof(EpplusIgnore)))
            .ToArray();
 
        return @this.LoadFromCollection<T>(collection, false
            OfficeOpenXml.Table.TableStyles.None, 
            BindingFlags.Instance | BindingFlags.Public, 
            membersToInclude);
    }
 
}
cs



Sample 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Person
{
    [EpplusIgnore]
    public int Key { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}
 
class Program
{
    static void Main(string[] args)
    {
        var demoData = new List<Person> { 
new Person { Key = 1, Age = 40, Name = "Fred" }, 
new Person { Key = 2, Name = "Eve", Age = 21 } 
};
 
        FileInfo fInfo = new FileInfo(@"C:\Temp\Book1.xlsx");
        using (var excel = new ExcelPackage())
        {
            var ws = excel.Workbook.Worksheets.Add("People");
            ws.Cells[11].LoadFromCollectionFiltered(demoData);
 
            excel.SaveAs(fInfo);
        }
    }
}
cs



출처: https://entityframework.net/knowledge-base/25603492/ignoring-properties-when-calling-loadfromcollection-in-epplus



ASUS TM-AC1900(RT-AC68U) 멀린펌(Merlin firmware) 업데이트

장난감


언제부터인가 위와 같은 TM-AC1900 Web UI에서 멀린펌 업데이트가 안되서 찾아본 결과,  

ASUS에서 하드웨어 정책을 변경하였다고 합니다.

더구나 멀린펌 제작자는 TM-AC1900을 지원하지 않는다고 하니

기존처럼 Web UI상에서 멀린펌 업데이트가 안됩니다.

그래서 찾아본 방법!



  1. Upload RT-AC68U_384.6_0.trx to your router:
    pscp -scp -P 22 RT-AC68U_384.6_0.trx admin@192.168.1.1:/tmp/
  2. In SSH console:
    mtd-write2 RT-AC68U_384.6_0.trx linux
  3. Wait for the above command to complete, it should output something like "CRC OK linux".
  4. Power off the router with its physical on/off switch (don't try reboot or halt from the console).
  5. Wait for ~10 sec and power it back on.


Windows 10, WOL(Wake on LAN) 무작정 따라하기

잡다...
Windows 10 업데이트 후 언제부턴가 WOL이 작동하지 않아 인터넷을 이리 저리 찾아봤지만
나에게 딱 맞는 케이스가 없어서 이런 저런 설정을 짜집기 하였습니다.


우선 제어판을 엽니다. (키보드의 Win 키를 누른  후  "control"를 타이핑하면 맨 위에 제어판이 검색 됩니다.)



그 다음 "전원 옵션" 항목을 클릭하여 "전원 옵션" 창을 연 후 왼쪽의 "전원 단추 작동 설정"을 클릭합니다.


전원 단추 정의 및 암호 보호 설정창이 뜨면 "현재 사용할 수 없는 설정 변경"을 클릭합니다.


"빠른 시작 켜기(권장)"을 선택 해제하고 하단의 "변경 내용 저장" 버튼을 클릭합니다.


이렇게 종료 설정을 완료했으면 이제 랜카드의 설정을 변경해야 합니다.
다시 제어판으로 돌아와서 "장치 관리자" 항목을 클릭하여 "장치 관리자" 창을 엽니다.
그 후 "네트워크 어댑터" 항목을 클릭하여 하위 노드 목록을 확인합니다.


PC에 설치된 랜카드 제조사에 따라 Realtek, Intel 등 다른 네트워크 어댑터 설치되어 있기 때문에 
"Ethernet"이라는 단어가 들어간 네트워크 어댑터를 마우스 오른쪽 버튼으로 클릭하고 "속성"을 선택합니다.

 
"속성" 창에서 "고급" 탭을 선택하고 아래 항목들에 대해 설정을 변경합니다.

    - Wake on Magic Packet: 활성화됨
    - Wake on Pattern Match: 활성화됨
    - 에너지 효율적인 이더넷: 오프


그 다음 "전원 관리" 탭을 선택하고
"전원을 절약하기 위해 컴퓨터가 이 장치를 끌 수 있음"을 선택 해제합니다.




'잡다...' 카테고리의 다른 글

미박스용 USB 전원 케이블  (0) 2020.04.06
크롬북 액정 수리  (0) 2016.09.10
Raspberry Pi에서 64GB, 128GB 등 고용량 SD 카드 사용하기  (0) 2016.07.05

[군자역] 호남집, 뼈해장국

먹거리

사거리를 넘어가야 선택지가 넓어지지만

오늘은 귀찮은 마음에 동네 주변을 돌아다니다가 결국 이 집을 갔습니다.



소머리국, 닭곰탕 등 탕 전문점인데 지금까지 몇 번 방문할 때마다 뒷맛이 깔끔하지 않아 오늘을 마지막으로 생각하고 뼈해장국을 주문했습니다.



이 집의 특징은 위와 같이 수저를 따뜻한 물이 든 통에 내온다는 것입니다.
왠지 살균된 느낌입니다.


깍두기만 달랑 나오는 다른 탕 전문점에 비해서는 성의(?) 있는 반찬들입니다.




드디어 나온 뼈해장국


과하지 않은 맛과 깻잎 향이 어우러져 생각 이상으로 맛있었습니다.

다음부터 이 집에서는 뼈해장국을 주문하는걸로 ....

'먹거리' 카테고리의 다른 글

[동대문] 사마르칸트 시티(Samarkand City)  (0) 2017.01.16
[군자역] 우렁쌈밥  (0) 2016.11.27
[군자역] 홍스시  (0) 2016.08.15
[군자역] 꿀쌈함흥면옥  (0) 2016.07.27
[이수역] 누룽지닭굼터, 누룽지불닭  (0) 2016.07.19

PushSharp로 APNs 이용중 오류 해결 - 패키지에 제공된 자격 증명을 인식할 수 없습니다

C#, ASP.NET

System.ComponentModel.Win32Exception: 패키지에 제공된 자격 증명을 인식할 없습니다


PushSharp.Apple.ApnsNotificationException: Apns notification error: 'ConnectionError' ---> System.ComponentModel.Win32Exception: 패키지에 제공된 자격 증명을 인식할 수 없습니다

   위치: System.Net.SSPIWrapper.AcquireCredentialsHandle(SSPIInterface SecModule, String package, CredentialUse intent, SecureCredential scc)

   위치: System.Net.Security.SecureChannel.AcquireCredentialsHandle(CredentialUse credUsage, SecureCredential& secureCredential)

   위치: System.Net.Security.SecureChannel.AcquireClientCredentials(Byte[]& thumbPrint)

   위치: System.Net.Security.SecureChannel.GenerateToken(Byte[] input, Int32 offset, Int32 count, Byte[]& output)

   위치: System.Net.Security.SecureChannel.NextMessage(Byte[] incoming, Int32 offset, Int32 count)

   위치: System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)

   위치: System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)

   위치: System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)

   위치: System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)

   위치: System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)

   위치: System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)

   위치: System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)

   위치: System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)

   위치: System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)

   위치: System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)

   위치: System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)

   위치: PushSharp.Apple.ApnsConnection.<connect>d__25.MoveNext()

--- 예외가 throw된 이전 위치의 스택 추적 끝 ---

   위치: System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

   위치: System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

   위치: PushSharp.Apple.ApnsConnection.<SendBatch>d__21.MoveNext()

   --- 내부 예외 스택 추적의 끝 ---

   위치: PushSharp.Apple.ApnsServiceConnection.<Send>d__2.MoveNext()



PushSharp을 이용해서 iOS 기기에 푸시를 보낼 때 위와 같은 오류가 발생했습니다.


apple에서 발급 받은 인증서 권한 문제로 보여 구글링을 해보면 다양한 해법이 있습니다.


그 중 대부분이 apple에서 인증서를 발급 받을 때 private만 추출해야 하는데 다 추출해서 발생한 문제입니다.



저 같은 경우는 로컬 컴퓨터에서 테스트시 정상 발송되었기 때문에 인증서 문제는 아니었습니다.


제가 성공한 방법은 PushSharp 샘플처럼 인증서 파일을 직접 사용하는 것이 아니라 저장소에 인증서를 등록하고 불러와서 사용하는 방법입니다.


저장소에 등록한 인증서를 지문(THUMBPRINT)를 통해 가져오는 코드는 아래와 같습니다.



1
2
3
4
5
6
7
8
string thumbprint = "YOUR THUMBPRINT";
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var certificate = store.Certificates.Find(
    X509FindType.FindByThumbprint, thumbprint, validOnly: false)
    .Cast<X509Certificate2>().SingleOrDefault();
var apnsConfig = new ApnsConfiguration(
    ApnsConfiguration.ApnsServerEnvironment.Production, certificate);
cs


출처: https://stackoverflow.com/questions/23329040/pushsharp-apns-production-the-credentials-supplied-to-the-package-were-not-reco



전 인증서를 로컬 컴퓨터에 저장하였기 때문에 위 코드에서 StoreLocation.CurrentUserStoreLocation.LocalMachine 으로 변경하였습니다.


지문(THUMBPRINT)는 인증서를 더블 클릭 후 나오는 인증서창의 자세히탭에서 확인할 수 있습니다.

(단, thumbprint 변수에 지문을 넣을 때는 공백 없이 입력해야 합니다.)